aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Ravnborg <sam@mars.ravnborg.org>2006-01-28 16:15:55 -0500
committerSam Ravnborg <sam@mars.ravnborg.org>2006-02-19 03:51:18 -0500
commit040fcc819a2e7783a570f4bdcdd1f2a7f5f06837 (patch)
tree58a6cb2e7394c589c8ef49b308512c83af0c7087
parent5c3ead8c72788d36d34c9f1689fb529d1339b405 (diff)
kbuild: improved modversioning support for external modules
With following patch a second option is enabled to obtain symbol information from a second external module when a external module is build. The recommended approach is to use a common kbuild file but that may be impractical in certain cases. With this patch one can copy over a Module.symvers from one external module to make symbols (and symbol versions) available for another external module. Updated documentation in Documentation/kbuild/modules.txt Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
-rw-r--r--Documentation/kbuild/modules.txt87
-rw-r--r--scripts/Makefile.modpost7
-rw-r--r--scripts/mod/modpost.c123
3 files changed, 158 insertions, 59 deletions
diff --git a/Documentation/kbuild/modules.txt b/Documentation/kbuild/modules.txt
index 87d858df4e3..fcccf2432f9 100644
--- a/Documentation/kbuild/modules.txt
+++ b/Documentation/kbuild/modules.txt
@@ -23,7 +23,10 @@ In this document you will find information about:
23 === 6. Module installation 23 === 6. Module installation
24 --- 6.1 INSTALL_MOD_PATH 24 --- 6.1 INSTALL_MOD_PATH
25 --- 6.2 INSTALL_MOD_DIR 25 --- 6.2 INSTALL_MOD_DIR
26 === 7. Module versioning 26 === 7. Module versioning & Module.symvers
27 --- 7.1 Symbols fron the kernel (vmlinux + modules)
28 --- 7.2 Symbols and external modules
29 --- 7.3 Symbols from another external module
27 === 8. Tips & Tricks 30 === 8. Tips & Tricks
28 --- 8.1 Testing for CONFIG_FOO_BAR 31 --- 8.1 Testing for CONFIG_FOO_BAR
29 32
@@ -89,7 +92,8 @@ when building an external module.
89 make -C $KDIR M=$PWD modules_install 92 make -C $KDIR M=$PWD modules_install
90 Install the external module(s). 93 Install the external module(s).
91 Installation default is in /lib/modules/<kernel-version>/extra, 94 Installation default is in /lib/modules/<kernel-version>/extra,
92 but may be prefixed with INSTALL_MOD_PATH - see separate chapter. 95 but may be prefixed with INSTALL_MOD_PATH - see separate
96 chapter.
93 97
94 make -C $KDIR M=$PWD clean 98 make -C $KDIR M=$PWD clean
95 Remove all generated files for the module - the kernel 99 Remove all generated files for the module - the kernel
@@ -433,7 +437,7 @@ External modules are installed in the directory:
433 => Install dir: /lib/modules/$(KERNELRELEASE)/gandalf 437 => Install dir: /lib/modules/$(KERNELRELEASE)/gandalf
434 438
435 439
436=== 7. Module versioning 440=== 7. Module versioning & Module.symvers
437 441
438Module versioning is enabled by the CONFIG_MODVERSIONS tag. 442Module versioning is enabled by the CONFIG_MODVERSIONS tag.
439 443
@@ -443,11 +447,80 @@ when a module is loaded/used then the CRC values contained in the kernel are
443compared with similar values in the module. If they are not equal then the 447compared with similar values in the module. If they are not equal then the
444kernel refuses to load the module. 448kernel refuses to load the module.
445 449
446During a kernel build a file named Module.symvers will be generated. This 450Module.symvers contains a list of all exported symbols from a kernel build.
447file includes the symbol version of all symbols within the kernel. If the
448Module.symvers file is saved from the last full kernel compile one does not
449have to do a full kernel compile to build a module version's compatible module.
450 451
452--- 7.1 Symbols fron the kernel (vmlinux + modules)
453
454 During a kernel build a file named Module.symvers will be generated.
455 Module.symvers contains all exported symbols from the kernel and
456 compiled modules. For each symbols the corresponding CRC value
457 is stored too.
458
459 The syntax of the Module.symvers file is:
460 <CRC> <Symbol> <module>
461 Sample:
462 0x2d036834 scsi_remove_host drivers/scsi/scsi_mod
463
464 For a kernel build without CONFIG_MODVERSIONING enabled the crc
465 would read: 0x00000000
466
467 Module.symvers serve two purposes.
468 1) It list all exported symbols both from vmlinux and all modules
469 2) It list CRC if CONFIG_MODVERSION is enabled
470
471--- 7.2 Symbols and external modules
472
473 When building an external module the build system needs access to
474 the symbols from the kernel to check if all external symbols are
475 defined. This is done in the MODPOST step and to obtain all
476 symbols modpost reads Module.symvers from the kernel.
477 If a Module.symvers file is present in the directory where
478 the external module is being build this file will be read too.
479 During the MODPOST step a new Module.symvers file will be written
480 containing all exported symbols that was not defined in the kernel.
481
482--- 7.3 Symbols from another external module
483
484 Sometimes one external module uses exported symbols from another
485 external module. Kbuild needs to have full knowledge on all symbols
486 to avoid spitting out warnings about undefined symbols.
487 Two solutions exist to let kbuild know all symbols of more than
488 one external module.
489 The method with a top-level kbuild file is recommended but may be
490 impractical in certain situations.
491
492 Use a top-level Kbuild file
493 If you have two modules: 'foo', 'bar' and 'foo' needs symbols
494 from 'bar' then one can use a common top-level kbuild file so
495 both modules are compiled in same build.
496
497 Consider following directory layout:
498 ./foo/ <= contains the foo module
499 ./bar/ <= contains the bar module
500 The top-level Kbuild file would then look like:
501
502 #./Kbuild: (this file may also be named Makefile)
503 obj-y := foo/ bar/
504
505 Executing:
506 make -C $KDIR M=`pwd`
507
508 will then do the expected and compile both modules with full
509 knowledge on symbols from both modules.
510
511 Use an extra Module.symvers file
512 When an external module is build a Module.symvers file is
513 generated containing all exported symbols which are not
514 defined in the kernel.
515 To get access to symbols from module 'bar' one can copy the
516 Module.symvers file from the compilation of the 'bar' module
517 to the directory where the 'foo' module is build.
518 During the module build kbuild will read the Module.symvers
519 file in the directory of the external module and when the
520 build is finished a new Module.symvers file is created
521 containing the sum of all symbols defined and not part of the
522 kernel.
523
451=== 8. Tips & Tricks 524=== 8. Tips & Tricks
452 525
453--- 8.1 Testing for CONFIG_FOO_BAR 526--- 8.1 Testing for CONFIG_FOO_BAR
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index bf96a61d4b8..563e3c5bd8d 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -39,7 +39,8 @@ include .config
39include scripts/Kbuild.include 39include scripts/Kbuild.include
40include scripts/Makefile.lib 40include scripts/Makefile.lib
41 41
42symverfile := $(objtree)/Module.symvers 42kernelsymfile := $(objtree)/Module.symvers
43modulesymfile := $(KBUILD_EXTMOD)/Modules.symvers
43 44
44# Step 1), find all modules listed in $(MODVERDIR)/ 45# Step 1), find all modules listed in $(MODVERDIR)/
45__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) 46__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
@@ -54,7 +55,9 @@ quiet_cmd_modpost = MODPOST
54 cmd_modpost = scripts/mod/modpost \ 55 cmd_modpost = scripts/mod/modpost \
55 $(if $(CONFIG_MODVERSIONS),-m) \ 56 $(if $(CONFIG_MODVERSIONS),-m) \
56 $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,) \ 57 $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,) \
57 $(if $(KBUILD_EXTMOD),-i,-o) $(symverfile) \ 58 $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \
59 $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \
60 $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \
58 $(filter-out FORCE,$^) 61 $(filter-out FORCE,$^)
59 62
60.PHONY: __modpost 63.PHONY: __modpost
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 4a2f2e38d27..976adf152db 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -20,6 +20,8 @@ int modversions = 0;
20int have_vmlinux = 0; 20int have_vmlinux = 0;
21/* Is CONFIG_MODULE_SRCVERSION_ALL set? */ 21/* Is CONFIG_MODULE_SRCVERSION_ALL set? */
22static int all_versions = 0; 22static int all_versions = 0;
23/* If we are modposting external module set to 1 */
24static int external_module = 0;
23 25
24void fatal(const char *fmt, ...) 26void fatal(const char *fmt, ...)
25{ 27{
@@ -45,6 +47,18 @@ void warn(const char *fmt, ...)
45 va_end(arglist); 47 va_end(arglist);
46} 48}
47 49
50static int is_vmlinux(const char *modname)
51{
52 const char *myname;
53
54 if ((myname = strrchr(modname, '/')))
55 myname++;
56 else
57 myname = modname;
58
59 return strcmp(myname, "vmlinux") == 0;
60}
61
48void *do_nofail(void *ptr, const char *expr) 62void *do_nofail(void *ptr, const char *expr)
49{ 63{
50 if (!ptr) { 64 if (!ptr) {
@@ -100,6 +114,9 @@ struct symbol {
100 unsigned int crc; 114 unsigned int crc;
101 int crc_valid; 115 int crc_valid;
102 unsigned int weak:1; 116 unsigned int weak:1;
117 unsigned int vmlinux:1; /* 1 if symbol is defined in vmlinux */
118 unsigned int kernel:1; /* 1 if symbol is from kernel
119 * (only for external modules) **/
103 char name[0]; 120 char name[0];
104}; 121};
105 122
@@ -135,8 +152,7 @@ static struct symbol *alloc_symbol(const char *name, unsigned int weak,
135} 152}
136 153
137/* For the hash of exported symbols */ 154/* For the hash of exported symbols */
138static void new_symbol(const char *name, struct module *module, 155static struct symbol *new_symbol(const char *name, struct module *module)
139 unsigned int *crc)
140{ 156{
141 unsigned int hash; 157 unsigned int hash;
142 struct symbol *new; 158 struct symbol *new;
@@ -144,10 +160,7 @@ static void new_symbol(const char *name, struct module *module,
144 hash = tdb_hash(name) % SYMBOL_HASH_SIZE; 160 hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
145 new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]); 161 new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
146 new->module = module; 162 new->module = module;
147 if (crc) { 163 return new;
148 new->crc = *crc;
149 new->crc_valid = 1;
150 }
151} 164}
152 165
153static struct symbol *find_symbol(const char *name) 166static struct symbol *find_symbol(const char *name)
@@ -169,19 +182,27 @@ static struct symbol *find_symbol(const char *name)
169 * Add an exported symbol - it may have already been added without a 182 * Add an exported symbol - it may have already been added without a
170 * CRC, in this case just update the CRC 183 * CRC, in this case just update the CRC
171 **/ 184 **/
172static void add_exported_symbol(const char *name, struct module *module, 185static struct symbol *sym_add_exported(const char *name, struct module *mod)
173 unsigned int *crc)
174{ 186{
175 struct symbol *s = find_symbol(name); 187 struct symbol *s = find_symbol(name);
176 188
177 if (!s) { 189 if (!s)
178 new_symbol(name, module, crc); 190 s = new_symbol(name, mod);
179 return; 191
180 } 192 s->vmlinux = is_vmlinux(mod->name);
181 if (crc) { 193 s->kernel = 0;
182 s->crc = *crc; 194 return s;
183 s->crc_valid = 1; 195}
184 } 196
197static void sym_update_crc(const char *name, struct module *mod,
198 unsigned int crc)
199{
200 struct symbol *s = find_symbol(name);
201
202 if (!s)
203 s = new_symbol(name, mod);
204 s->crc = crc;
205 s->crc_valid = 1;
185} 206}
186 207
187void *grab_file(const char *filename, unsigned long *size) 208void *grab_file(const char *filename, unsigned long *size)
@@ -332,8 +353,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
332 /* CRC'd symbol */ 353 /* CRC'd symbol */
333 if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { 354 if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
334 crc = (unsigned int) sym->st_value; 355 crc = (unsigned int) sym->st_value;
335 add_exported_symbol(symname + strlen(CRC_PFX), 356 sym_update_crc(symname + strlen(CRC_PFX), mod, crc);
336 mod, &crc);
337 } 357 }
338 break; 358 break;
339 case SHN_UNDEF: 359 case SHN_UNDEF:
@@ -377,8 +397,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
377 default: 397 default:
378 /* All exported symbols */ 398 /* All exported symbols */
379 if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) { 399 if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) {
380 add_exported_symbol(symname + strlen(KSYMTAB_PFX), 400 sym_add_exported(symname + strlen(KSYMTAB_PFX), mod);
381 mod, NULL);
382 } 401 }
383 if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0) 402 if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0)
384 mod->has_init = 1; 403 mod->has_init = 1;
@@ -388,18 +407,6 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
388 } 407 }
389} 408}
390 409
391static int is_vmlinux(const char *modname)
392{
393 const char *myname;
394
395 if ((myname = strrchr(modname, '/')))
396 myname++;
397 else
398 myname = modname;
399
400 return strcmp(myname, "vmlinux") == 0;
401}
402
403/** 410/**
404 * Parse tag=value strings from .modinfo section 411 * Parse tag=value strings from .modinfo section
405 **/ 412 **/
@@ -450,9 +457,7 @@ static void read_symbols(char *modname)
450 /* When there's no vmlinux, don't print warnings about 457 /* When there's no vmlinux, don't print warnings about
451 * unresolved symbols (since there'll be too many ;) */ 458 * unresolved symbols (since there'll be too many ;) */
452 if (is_vmlinux(modname)) { 459 if (is_vmlinux(modname)) {
453 unsigned int fake_crc = 0;
454 have_vmlinux = 1; 460 have_vmlinux = 1;
455 add_exported_symbol("struct_module", mod, &fake_crc);
456 mod->skip = 1; 461 mod->skip = 1;
457 } 462 }
458 463
@@ -665,7 +670,7 @@ static void write_if_changed(struct buffer *b, const char *fname)
665 fclose(file); 670 fclose(file);
666} 671}
667 672
668static void read_dump(const char *fname) 673static void read_dump(const char *fname, unsigned int kernel)
669{ 674{
670 unsigned long size, pos = 0; 675 unsigned long size, pos = 0;
671 void *file = grab_file(fname, &size); 676 void *file = grab_file(fname, &size);
@@ -679,6 +684,7 @@ static void read_dump(const char *fname)
679 char *symname, *modname, *d; 684 char *symname, *modname, *d;
680 unsigned int crc; 685 unsigned int crc;
681 struct module *mod; 686 struct module *mod;
687 struct symbol *s;
682 688
683 if (!(symname = strchr(line, '\t'))) 689 if (!(symname = strchr(line, '\t')))
684 goto fail; 690 goto fail;
@@ -699,13 +705,28 @@ static void read_dump(const char *fname)
699 mod = new_module(NOFAIL(strdup(modname))); 705 mod = new_module(NOFAIL(strdup(modname)));
700 mod->skip = 1; 706 mod->skip = 1;
701 } 707 }
702 add_exported_symbol(symname, mod, &crc); 708 s = sym_add_exported(symname, mod);
709 s->kernel = kernel;
710 sym_update_crc(symname, mod, crc);
703 } 711 }
704 return; 712 return;
705fail: 713fail:
706 fatal("parse error in symbol dump file\n"); 714 fatal("parse error in symbol dump file\n");
707} 715}
708 716
717/* For normal builds always dump all symbols.
718 * For external modules only dump symbols
719 * that are not read from kernel Module.symvers.
720 **/
721static int dump_sym(struct symbol *sym)
722{
723 if (!external_module)
724 return 1;
725 if (sym->vmlinux || sym->kernel)
726 return 0;
727 return 1;
728}
729
709static void write_dump(const char *fname) 730static void write_dump(const char *fname)
710{ 731{
711 struct buffer buf = { }; 732 struct buffer buf = { };
@@ -715,15 +736,10 @@ static void write_dump(const char *fname)
715 for (n = 0; n < SYMBOL_HASH_SIZE ; n++) { 736 for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
716 symbol = symbolhash[n]; 737 symbol = symbolhash[n];
717 while (symbol) { 738 while (symbol) {
718 symbol = symbol->next; 739 if (dump_sym(symbol))
719 } 740 buf_printf(&buf, "0x%08x\t%s\t%s\n",
720 } 741 symbol->crc, symbol->name,
721 742 symbol->module->name);
722 for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
723 symbol = symbolhash[n];
724 while (symbol) {
725 buf_printf(&buf, "0x%08x\t%s\t%s\n", symbol->crc,
726 symbol->name, symbol->module->name);
727 symbol = symbol->next; 743 symbol = symbol->next;
728 } 744 }
729 } 745 }
@@ -735,13 +751,18 @@ int main(int argc, char **argv)
735 struct module *mod; 751 struct module *mod;
736 struct buffer buf = { }; 752 struct buffer buf = { };
737 char fname[SZ]; 753 char fname[SZ];
738 char *dump_read = NULL, *dump_write = NULL; 754 char *kernel_read = NULL, *module_read = NULL;
755 char *dump_write = NULL;
739 int opt; 756 int opt;
740 757
741 while ((opt = getopt(argc, argv, "i:mo:a")) != -1) { 758 while ((opt = getopt(argc, argv, "i:I:mo:a")) != -1) {
742 switch(opt) { 759 switch(opt) {
743 case 'i': 760 case 'i':
744 dump_read = optarg; 761 kernel_read = optarg;
762 break;
763 case 'I':
764 module_read = optarg;
765 external_module = 1;
745 break; 766 break;
746 case 'm': 767 case 'm':
747 modversions = 1; 768 modversions = 1;
@@ -757,8 +778,10 @@ int main(int argc, char **argv)
757 } 778 }
758 } 779 }
759 780
760 if (dump_read) 781 if (kernel_read)
761 read_dump(dump_read); 782 read_dump(kernel_read, 1);
783 if (module_read)
784 read_dump(module_read, 0);
762 785
763 while (optind < argc) { 786 while (optind < argc) {
764 read_symbols(argv[optind++]); 787 read_symbols(argv[optind++]);