parameter of module_init() and module_exit() must not be a macro
Warlich, Christof
christof.warlich at siemens.com
Thu Oct 15 05:48:53 EDT 2015
I'd just like to get some feedback on the following issue and if the patch that I'm suggesting would be appropriate to be considered for upstream submission:
While writing a driver template, I just came across an issue with the module_init() and module_exit() macros: They don't work properly when the parameter being passed to them is a macro itself. Here is a minimal example that shows the issue:
$ cat test.c
#include <linux/module.h>
#define DRIVER_INIT test_init
static int __init DRIVER_INIT(void)
{
return 0;
}
//module_init(test_init); // This works, ...
module_init(DRIVER_INIT); // ... but this doesn't.
Building the module gives the following errors:
$ make -C /lib/modules/$(uname -r)/build MODULES=test M=$(pwd) modules
make: Entering directory `/usr/src/linux-headers-3.13.0-65-generic'
CC [M] /home/adwach13/tmp/module/tst.o
In file included from /usr/src/linux-headers-3.13.0-65-generic/arch/x86/include/asm/ptrace.h:63:0,
from /usr/src/linux-headers-3.13.0-65-generic/arch/x86/include/asm/alternative.h:8,
from /usr/src/linux-headers-3.13.0-65-generic/arch/x86/include/asm/bitops.h:16,
from include/linux/bitops.h:36,
from include/linux/kernel.h:10,
from include/linux/cache.h:4,
from include/linux/time.h:4,
from include/linux/stat.h:18,
from include/linux/module.h:10,
from /home/adwach13/tmp/module/tst.c:1:
include/linux/init.h:298:6: error: 'init_module' aliased to undefined symbol 'DRIVER_INIT'
int init_module(void) __attribute__((alias(#initfn)));
^
/home/adwach13/tmp/module/tst.c:8:1: note: in expansion of macro 'module_init'
module_init(DRIVER_INIT);
^
make[1]: *** [/home/adwach13/tmp/module/tst.o] Error 1
make: *** [_module_/home/adwach13/tmp/module] Error 2
make: Leaving directory `/usr/src/linux-headers-3.13.0-65-generic'
The reason for this behavior is because macro stringification is not done properly in the module_init() and module_exit() macro definitions in include/linux/init.h. But a fix would be easy:
$ diff -Nau /usr/src/linux-headers-3.13.0-65-generic/include/linux/init.h.orig /usr/src/linux-headers-3.13.0-65-generic/include/linux/init.h
--- /usr/src/linux-headers-3.13.0-65-generic/include/linux/init.h.orig 2015-10-15 11:40:36.300458826 +0200
+++ /usr/src/linux-headers-3.13.0-65-generic/include/linux/init.h 2015-10-15 11:42:05.370985262 +0200
@@ -291,17 +291,20 @@
#define security_initcall(fn) module_init(fn)
+#define _STRINGIFY(x) #x
+#define STRINGIFY(x) _STRINGIFY(x)
+
/* Each module must use one module_init(). */
#define module_init(initfn) \
static inline initcall_t __inittest(void) \
{ return initfn; } \
- int init_module(void) __attribute__((alias(#initfn)));
+ int init_module(void) __attribute__((alias(STRINGIFY(initfn))));
/* This is only required if you want to be unloadable. */
#define module_exit(exitfn) \
static inline exitcall_t __exittest(void) \
{ return exitfn; } \
- void cleanup_module(void) __attribute__((alias(#exitfn)));
+ void cleanup_module(void) __attribute__((alias(STRINGIFY(exitfn))));
#define __setup_param(str, unique_id, fn) /* nothing */
#define __setup(str, func) /* nothing */
What do you think: Is this patch worth to be suggested? Or is the current behavior intended?
More information about the Kernelnewbies
mailing list