diff options
author | Sam Ravnborg <sam@mars.ravnborg.org> | 2006-01-28 16:15:55 -0500 |
---|---|---|
committer | Sam Ravnborg <sam@mars.ravnborg.org> | 2006-02-19 03:51:18 -0500 |
commit | 040fcc819a2e7783a570f4bdcdd1f2a7f5f06837 (patch) | |
tree | 58a6cb2e7394c589c8ef49b308512c83af0c7087 | |
parent | 5c3ead8c72788d36d34c9f1689fb529d1339b405 (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.txt | 87 | ||||
-rw-r--r-- | scripts/Makefile.modpost | 7 | ||||
-rw-r--r-- | scripts/mod/modpost.c | 123 |
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 | ||
438 | Module versioning is enabled by the CONFIG_MODVERSIONS tag. | 442 | Module 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 | |||
443 | compared with similar values in the module. If they are not equal then the | 447 | compared with similar values in the module. If they are not equal then the |
444 | kernel refuses to load the module. | 448 | kernel refuses to load the module. |
445 | 449 | ||
446 | During a kernel build a file named Module.symvers will be generated. This | 450 | Module.symvers contains a list of all exported symbols from a kernel build. |
447 | file includes the symbol version of all symbols within the kernel. If the | ||
448 | Module.symvers file is saved from the last full kernel compile one does not | ||
449 | have 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 | |||
39 | include scripts/Kbuild.include | 39 | include scripts/Kbuild.include |
40 | include scripts/Makefile.lib | 40 | include scripts/Makefile.lib |
41 | 41 | ||
42 | symverfile := $(objtree)/Module.symvers | 42 | kernelsymfile := $(objtree)/Module.symvers |
43 | modulesymfile := $(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; | |||
20 | int have_vmlinux = 0; | 20 | int have_vmlinux = 0; |
21 | /* Is CONFIG_MODULE_SRCVERSION_ALL set? */ | 21 | /* Is CONFIG_MODULE_SRCVERSION_ALL set? */ |
22 | static int all_versions = 0; | 22 | static int all_versions = 0; |
23 | /* If we are modposting external module set to 1 */ | ||
24 | static int external_module = 0; | ||
23 | 25 | ||
24 | void fatal(const char *fmt, ...) | 26 | void 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 | ||
50 | static 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 | |||
48 | void *do_nofail(void *ptr, const char *expr) | 62 | void *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 */ |
138 | static void new_symbol(const char *name, struct module *module, | 155 | static 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 | ||
153 | static struct symbol *find_symbol(const char *name) | 166 | static 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 | **/ |
172 | static void add_exported_symbol(const char *name, struct module *module, | 185 | static 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 | |
197 | static 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 | ||
187 | void *grab_file(const char *filename, unsigned long *size) | 208 | void *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 | ||
391 | static 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 | ||
668 | static void read_dump(const char *fname) | 673 | static 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; |
705 | fail: | 713 | fail: |
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 | **/ | ||
721 | static 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 | |||
709 | static void write_dump(const char *fname) | 730 | static 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++]); |