summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Germaschewski <kai@tp1.ruhr-uni-bochum.de>2003-01-24 09:54:04 -0600
committerKai Germaschewski <kai@tp1.ruhr-uni-bochum.de>2003-01-24 09:54:04 -0600
commitdcc38eae49e06d798497373771ae03f5508a2ec7 (patch)
tree5f2ea4f7f329bff12bc4c1d2da2f5186344c452b
parente4ccd604a353b3d4e61e99d04ac9a2bdd8b66ec4 (diff)
kbuild/modules: Record versions for unresolved symbols
In the case of CONFIG_MODVERSIONING, the build step will only generate preliminary <module>.o objects, and an additional postprocessing step is necessary to record the versions of the unresolved symbols and add them into the final <module>.ko The version information for unresolved symbols is again recorded into a special section, "__versions", which contains an array of symbol name strings and checksum (struct modversion_info). Size is here not an issue, since this section will not be stored permanently in kernel memory. Makefile.modver takes care of the following steps: o Collect the version information for all exported symbols from vmlinux and all modules which export symbols. o For each module, generate a C file which contains the modversion information for all unresolved symbols in that module. o For each module, compile that C file to an object file o Finally, link the <module>.ko using the preliminary <module.o> + the version information above. The first two steps are currently done by not very efficient scripting, so there's room for performance improvement using some helper C code.
-rw-r--r--Makefile15
-rw-r--r--include/linux/module.h7
-rw-r--r--scripts/Makefile.modver89
3 files changed, 108 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 308673b8b2e5..3387d56da0b0 100644
--- a/Makefile
+++ b/Makefile
@@ -262,7 +262,7 @@ endif
# When we're building modules with modversions, we need to consider
# the built-in objects during the descend as well, in order to
-# make sure the checksums are uptodate before we use them.
+# make sure the checksums are uptodate before we record them.
ifdef CONFIG_MODVERSIONING
ifeq ($(KBUILD_MODULES),1)
@@ -508,8 +508,16 @@ ifdef CONFIG_MODULES
# Build modules
-.PHONY: modules
-modules: $(SUBDIRS)
+.PHONY: modules __modversions
+modules: $(SUBDIRS) __modversions
+
+ifdef CONFIG_MODVERSIONING
+
+__modversions: vmlinux $(SUBDIRS)
+ @echo ' Recording module symbol versions.';
+ $(Q)$(MAKE) -rR -f scripts/Makefile.modver
+
+endif
# Install modules
@@ -690,6 +698,7 @@ MRPROPER_FILES += \
# Directories removed with 'make mrproper'
MRPROPER_DIRS += \
+ $(MODVERDIR) \
.tmp_export-objs \
include/config \
include/linux/modules
diff --git a/include/linux/module.h b/include/linux/module.h
index af4272910b27..e8726d9909d7 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -33,12 +33,19 @@
#endif
#define MODULE_NAME_LEN (64 - sizeof(unsigned long))
+
struct kernel_symbol
{
unsigned long value;
const char *name;
};
+struct modversion_info
+{
+ unsigned long crc;
+ char name[MODULE_NAME_LEN];
+};
+
/* These are either module local, or the kernel's dummy ones. */
extern int init_module(void);
extern void cleanup_module(void);
diff --git a/scripts/Makefile.modver b/scripts/Makefile.modver
index 5405cbce2170..372d6aff5a32 100644
--- a/scripts/Makefile.modver
+++ b/scripts/Makefile.modver
@@ -2,3 +2,92 @@
# Module versions
# ===========================================================================
+.PHONY: __modversions
+__modversions:
+
+include scripts/Makefile.lib
+
+#
+
+modules := $(patsubst ./%,%,$(shell cd $(MODVERDIR); find . -name \*.ko))
+
+__modversions: $(modules)
+ @:
+
+quiet_cmd_ld_ko_o = LD [M] $@
+ cmd_ld_ko_o = $(LD) $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ \
+ $(filter-out FORCE,$^)
+
+init/vermagic.o: ;
+
+$(modules): %.ko :%.o $(MODVERDIR)/%.o init/vermagic.o FORCE
+ $(call if_changed,ld_ko_o)
+
+targets += $(modules)
+
+
+quiet_cmd_cc_o_c = CC $@
+ cmd_cc_o_c = $(CC) $(CFLAGS) -c -o $@ $<
+
+$(addprefix $(MODVERDIR)/,$(modules:.ko=.o)): %.o: %.c FORCE
+ $(call if_changed,cc_o_c)
+
+targets += $(addprefix $(MODVERDIR)/,$(modules:.ko=.o))
+
+define rule_mkver_o_c
+ echo ' MKVER $@'; \
+ ( echo "#include <linux/module.h>"; \
+ echo ""; \
+ echo "static const struct modversion_info ____versions[]"; \
+ echo "__attribute__((section(\"__versions\"))) = {"; \
+ for sym in `nm -u $<`; do \
+ grep "\"$$sym\"" .tmp_all-versions \
+ || echo "*** Warning: $(<:.o=.ko): \"$$sym\" unresolved!" >&2;\
+ done; \
+ echo "};"; \
+ ) > $@
+endef
+
+$(addprefix $(MODVERDIR)/,$(modules:.ko=.c)): \
+$(MODVERDIR)/%.c: %.o .tmp_all-versions FORCE
+ $(call if_changed_rule,mkver_o_c)
+
+targets += $(addprefix $(MODVERDIR)/,$(modules:.ko=.o.c))
+
+export-objs := $(shell for m in vmlinux $(modules:.ko=.o); do objdump -h $$m | grep -q __ksymtab && echo $$m; done)
+
+cmd_gen-all-versions = mksyms $(export-objs)
+define rule_gen-all-versions
+ echo ' MKSYMS $@'; \
+ for mod in $(export-objs); do \
+ modname=`basename $$mod`; \
+ nm $$mod \
+ | grep ' __crc_' \
+ | sed "s/\([^ ]*\) A __crc_\(.*\)/{ 0x\1, \"\2\" }, \/* $$modname *\//g;s/.* w __crc_\(.*\)/{ 0x0 , \"\1\" }, \/* $$modname *\//g"; \
+ done > $@; \
+ echo 'cmd_$@ := $(cmd_$(1))' > $(@D)/.$(@F).cmd
+endef
+
+.tmp_all-versions: $(export-objs) FORCE
+ $(call if_changed_rule,gen-all-versions)
+
+targets += .tmp_all-versions
+
+# Add FORCE to the prequisites of a target to force it to be always rebuilt.
+# ---------------------------------------------------------------------------
+
+.PHONY: FORCE
+
+FORCE:
+
+# Read all saved command lines and dependencies for the $(targets) we
+# may be building above, using $(if_changed{,_dep}). As an
+# optimization, we don't need to read them if the target does not
+# exist, we will rebuild anyway in that case.
+
+targets := $(wildcard $(sort $(targets)))
+cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
+
+ifneq ($(cmd_files),)
+ include $(cmd_files)
+endif