Marking loadable kernel module as in-tree - linux

This question is about linux kernel 4.10.
Loading an out-of-tree LKM causes kernel to print a warning:
module: loading out-of-tree module taints kernel.
This raises from this check in module.c:
if (!get_modinfo(info, "intree")) {
Reading get_modinfo it seams that "intree" is just a a magic-string livnig inside the .ko file.
Running readelf on a random LKM I found in my system shows this:
readelf -a imon.ko | grep intree
161: 00000000000006c0 9 OBJECT LOCAL DEFAULT 13 __UNIQUE_ID_intree1
While looking for intree in a simple, custom hello_world LKM returns no results.
Is this actually the case?
How are some modules marked as being in-tree? Is it done by adding a macro to the module (like MODULE_LICENCE), or by building the module in a specific way or something else?

In short, the build system contrives to add the line MODULE_INFO(intree, "Y"); to the "modulename.mod.c" file if and only if the module is being built intree.
There is an obvious way to fool the system by adding that line to one of your module's regular ".c" files, but I'm not sure why you'd want to.
Longer version....
External modules are normally built with a command similar to this:
$ make M=`pwd` modules
or the old syntax:
$ make SUBDIRS=`pwd` modules
The presence of a non-empty M or SUBDIRS causes the kernel's top-level "Makefile" to set the KBUILD_EXTMOD variable. It won't be set for a normal kernel build.
For stage 2 of module building (when the message "Building modules, stage 2" is output), make runs the "scripts/Makefile.modpost" makefile. That runs scripts/mod/modpost with different options when KBUILD_EXTMOD is set. In particular, the -I option is used when KBUILD_EXTMOD is set.
Looking at the source for modpost in "scripts/mod/modpost.c", the external_module variable has an initial value of 0, but the -I option sets it to 1. The function add_intree_flag() is called with the second parameter is_intree set to !external_module. The add_intree_flag() function writes MODULE_INFO(intree, "Y"); to the "modulename.mod.c" file if and only if its is_intree parameter is true.
So the difference between intree modules and external modules is the presence of the MODULE_INFO(intree, "Y"); macro call in the "modulename.mod.c" file. This gets compiled to "modulename.mod.o" and linked with the module's other object files to form the "modulename.ko" file.

Related

Linux Kernel Module ignores main module file when an additional source file is added [duplicate]

This question already has answers here:
Building a kernel module from several source files which one of them has the same name as the module
(6 answers)
Closed 1 year ago.
I'm trying to build a loadable kernel module that includes another source file. I have the following in a Makefile or Kbuild file:
obj-m += mymodule.o
mymodule-y += other_src_file.o
In this scenario, other_src_file.c will be compiled. Strangely, the main source file mymodule.c will not be compiled. Intentional syntax errors are not caught. An object file mymodule.o is still produced, as is the .KO file. Loading this module on the target platform has no effect.
If I instead remove the second line in the Makefile/Kbuild that includes the other source file, my intentional syntax errors are caught. In a minimal example, init_module() will run and dmesg shows what I put into printk. It would not print anything prior to removing the line with other_src_file.o, despite being unchanged.
So what I find is that by including an additional source file (whether it is being used or not), the main module/C file is effectively ignored. An LKM is produced, but it has no effect from what I can see. Using --debug confirms in the latter case that mymodule.c is used (pipe into grep returns literally anything) whereas the former shows that there is not a single reference to mymodule.c (but many to other_src_file.c)
I've also tried setting up the makefile as the following, but there's no behavioral difference.
obj-m += mymodule.o
mymodule-y += other_src_file.o
all:
make -C ../../../ M=($PWD) modules # -C points to the root of my kernel
clean:
clean -c ../../../ M=$(PWD) clean
The output of make looks like the following:
LD some/path/mymodule/built-in.o
CC[M] /some/path/mymodule/other_src_file.o <-- notice it's the only CC; nothing for mymodule.o
LD[M] /some/path/mymodule/mymodule.o
Building modules, stage 2
MODPOST 1 modules
CC /some/path/mymodule/mymodule.mod.o
LD[M] /some/path/mymodule/mymodule.ko
When that other src file is left out, there is a line that shows mymodule.o being compiled.
I'm running in an Ubuntu 20.04 (VM) on x86_64. The kernel is 3.1.10, make is 4.2.1.
I feel like I'm missing something simple (unfamiliar with linux building, fairly familiar with C and compiling otherwise). Would greatly appreciate a pointer here.
The line
obj-m += mymodule.o
tells KBuild system just to build a module named mymodule.
The sources compiled into that module depend from variable mymodule-y:
If the variable is set (like in your code), then source list it taken only from this variable. There is no "automatic" addition of mymodule.c source.
If the variable is not set, then, by default, the module is compiled from the source which has the same name.
Note, that one cannot build a module mymodule from several sources, one of which is mymodule.c, that is has the same name as the module itself.
Either module or the source file should be renamed. That situation is described in that question.

How to export a symbol from an external module?

I am coding outside the kernel source tree. There are two modules, the first one printt have a function printtty() to print string to the current tty, and the second module hello which invokes printtty() during initialization.
I have added EXPORT_SYMBOL(printtty) in module printt, and after insmod ./printt.ko, the information of printtty() can be seen in /proc/kallsyms.
The make process of module hello goes all right. But insmod ./hello.ko will cause an error like:
insmod: ERROR: could not insert module hello.ko: Invalid parameters
and dmesg shows
hello: no symbol version for printtty
hello: Unknown symbol printtty (err -22)`.
I've fixed this by
(1) Copy the .ko file to a location beneath /lib/modules/version/kernel
(2) Add the exported symbols to /lib/modules/version/build/Module.symvers
But I wonder is there any way to export a symbol just from an external module(without modifying kernel source tree)?
Add this line at the very top of your Makefile for your hello module:
KBUILD_EXTRA_SYMBOLS := /home/your-user/path/to/printt/Module.symvers
(be sure to put in the correct path to your printt module).
Now rebuild your hello module and it will be loaded just fine.
For details see Documentation/kbuild/modules.txt, "6.3 Symbols From Another External Module".

Warning building a kernel module that uses exported symbols

I have two kernel modules (say modA and modB). modA exports a symbol with EXPORT_SYMBOL(symA) and modB uses it. I have the header modA.h for modA:
...
extern void symA(int param);
...
and in modB.c:
#include "modA.h"
...
static int __init modB_init(void)
{
symA(10);
}
...
If i insmod modB all works fine, my modB is correctly linked in the kernel and the function symA is correctly called. However when i build modB the compiler raises a warning: symA is undefined. An LKM is an ELF relocatable so why the compiler raises this warning? How can be this removed?
This issue (and how to compile correctly in this case) is explained in 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.

Reusing custom makefile for static library with cmake

I guess this would be a generic question on including libraries with existing makefiles within cmake; but here's my context -
I'm trying to include scintilla in another CMake project, and I have the following problem:
On Linux, scintilla has a makefile in (say) the ${CMAKE_CURRENT_SOURCE_DIR}/scintilla/gtk directory; if you run make in that directory (as usual), you get a ${CMAKE_CURRENT_SOURCE_DIR}/scintilla/bin/scintilla.a file - which (I guess) is the static library.
Now, if I'd try to use cmake's ADD_LIBRARY, I'd have to manually specify the sources of scintilla within cmake - and I'd rather not mess with that, given I already have a makefile. So, I'd rather call the usual scintilla make - and then instruct CMAKE to somehow refer to the resulting scintilla.a. (I guess that this then would not ensure cross-platform compatibility - but note that currently cross-platform is not an issue for me; I'd just like to build scintilla as part of this project that already uses cmake, only within Linux)
So, I've tried a bit with this:
ADD_CUSTOM_COMMAND(
OUTPUT scintilla.a
COMMAND ${CMAKE_MAKE_PROGRAM}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/scintilla/gtk
COMMENT "Original scintilla makefile target" )
... but then, add_custom_command adds a "target with no output"; so I'm trying several approach to build upon that, all of which fail (errors given as comment):
ADD_CUSTOM_TARGET(scintilla STATIC DEPENDS scintilla.a) # Target "scintilla" of type UTILITY may not be linked into another target.
ADD_LIBRARY(scintilla STATIC DEPENDS scintilla.a) # Cannot find source file "DEPENDS".
ADD_LIBRARY(scintilla STATIC) # You have called ADD_LIBRARY for library scintilla without any source files.
ADD_DEPENDENCIES(scintilla scintilla.a)
I'm obviously quote a noob with cmake - so, is it possible at all to have cmake run a pre-existing makefile, and "capture" its output library file, such that other components of the cmake project can link against it?
Many thanks for any answers,
Cheers!
EDIT: possible duplicate: CMake: how do i depend on output from a custom target? - Stack Overflow - however, here the breakage seems to be due to the need to specifically have a library that the rest of the cmake project would recognize...
Another related: cmake - adding a custom command with the file name as a target - Stack Overflow; however, it specifically builds an executable from source files (which I wanted to avoid)..
You could also use imported targets and a custom target like this:
# set the output destination
set(SCINTILLA_LIBRARY ${CMAKE_CURRENT_SOURCE_DIR}/scintilla/gtk/scintilla.a)
# create a custom target called build_scintilla that is part of ALL
# and will run each time you type make
add_custom_target(build_scintilla ALL
COMMAND ${CMAKE_MAKE_PROGRAM}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/scintilla/gtk
COMMENT "Original scintilla makefile target")
# now create an imported static target
add_library(scintilla STATIC IMPORTED)
# Import target "scintilla" for configuration ""
set_property(TARGET scintilla APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG)
set_target_properties(scintilla PROPERTIES
IMPORTED_LOCATION_NOCONFIG "${SCINTILLA_LIBRARY}")
# now you can use scintilla as if it were a regular cmake built target in your project
add_dependencies(scintilla build_scintilla)
add_executable(foo foo.c)
target_link_libraries(foo scintilla)
# note, this will only work on linux/unix platforms, also it does building
# in the source tree which is also sort of bad style and keeps out of source
# builds from working.
OK, I think I have it somewhat; basically, in the CMakeLists.txt that build scintilla, I used this only:
ADD_CUSTOM_TARGET(
scintilla.a ALL
COMMAND ${CMAKE_MAKE_PROGRAM}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/scintilla/gtk
COMMENT "Original scintilla makefile target" )
... and then, the slightly more complicated part, was to find the correct cmake file elsewhere in the project, where the ${PROJECT_NAME} was defined - so as to add a dependency:
ADD_DEPENDENCIES(${PROJECT_NAME} scintilla.a)
... and finally, the library needs to be linked.
Note that in the commands heretofore, the scintilla.a is merely a name/label/identifier/string (so it could be anything else, like scintilla--a or something); but for linking - the full path to the actual `scintilla.a file is needed (which in this project ends up in a variable ${SCINTILLA_LIBRARY}). In this project, the linking basically occurs through a form of a
list(APPEND PROJ_LIBRARIES ${SCINTILLA_LIBRARY} )
... and I don't really know how cmake handles the actual linking afterwards (but it seems to work)
For consistency, I tried to use ${SCINTILLA_LIBRARY} instead of scintilla.a as identifier in the ADD_CUSTOM_TARGET, but got error: "Target names may not contain a slash. Use ADD_CUSTOM_COMMAND to generate files". So probably this could be solved smarter/more correct with ADD_CUSTOM_COMMAND - however, I read that it "defines a new command that can be executed during the build process. The outputs named should be listed as source files in the target for which they are to be generated."... And by now I'm totally confused so as to what is a file, what is a label, and what is a target - so I think I'll leave at this (and not fix it if it ain't broken :) )
Well, it'd still be nice to know a more correct way to do this eventually,
Cheers!

How to work around "scons: warning: Two different environments were specified for target"

Suppose I have an SConstruct file that looks like this:
env = Environment()
env.Program("a", ["a.c", "util.c"])
env.Program("b", ["b.c", "util.c"])
This build works properly with no SCons warning messages. However, if I modify this to specify different libraries for each Program build (the actual libraries are not relevant):
env.Program("a", ["a.c", "util.c"], LIBS="m")
env.Program("b", ["b.c", "util.c"], LIBS="c")
then I get the warning:
scons: warning: Two different environments were specified for target util.o,
but they appear to have the same action: $CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES
This appears to be caused by the Program builder automatically creating a new environment for building the sources, even though it is just the LIBS variable that is different (and so only the link step needs to have a different environment). I can work around this by doing something like:
util = env.Object("util.c")
env.Program("a", ["a.c"] + util, LIBS="m")
env.Program("b", ["b.c"] + util, LIBS="c")
This uses a single Object builder for building util.c, then using the precompiled object file in each Program build, thus avoiding the warning. However, this should not really be necessary. Is there a more elegant way to work around this problem? Or is this actually a bug in SCons that should be fixed?
Context: I have nearly 2000 C source files compiled into about 20 libraries and 120 executables with lots of shared sources. I created the SConstruct file from the previous proprietary build system using a conversion script I wrote. There are about 450 "Two different environments" warning messages produced by SCons for a full build using my current SConstruct.
I found a workaround that doesn't involve creating extra variables to hold the object file nodes:
env.Program("a", ["a.c", env.Object("util.c")], LIBS="m")
env.Program("b", ["b.c", env.Object("util.c")], LIBS="c")
This isolates the build of util.c within a single environment. Although it is specified twice, once for each Program, SCons doesn't warn about this because it's the same source built with the same env object. Of course SCons only compiles the source once in this case.
You may use the Split function and a custom helper to simplify the build process for large projects:
def create_objs(SRCS, path=""):
return [env.Object(path+src+".cpp") for src in SRCS]
prg1 = Split("file_1 file_2 file_N")
prg2 = Split("file_2 file_5 file_8")
env.Program("a", create_objs(prg1), LIBS="x")
env.Program("b", create_objs(prg2), LIBS="y")
The object files are created only once, and they can be used in multiple builds. Hope this helps...
One issue I found in my code was that I was not using the target object path correctly. Or in otherwords I had a variant dir directive, but instead of using BUILDPATH i ended up using my original source code path. This way Scons was finding the object generated in target BUILDPATH and source path.
Creating a static library out of the first set of files and linking the library to the next set of files (which have some files in common with the first set) to create a target works as well.
env.StaticLibrary ("a", ["a.c","util.c"], LIBS = "m")
env.Program ("b", ["b.c","util.c"], LIBS = ["c","a"])

Resources