Re: Making module versions (Was: OFFTOPIC: binary modules, bad idea!)

teunis (teunis@mauve.computersupportcentre.com)
Fri, 26 Dec 1997 01:49:37 -0700 (MST)


On Mon, 22 Dec 1997, Roderich Schupp wrote:
>
> Just for the record, the following is my understanding of how the current
> module version scheme works. Feel free to correct any mistakes. If this
> is already covered elsewhere in sufficient detail I'd appreciate a pointer.
> This is rather longish so you might want to skip to the end for my
> actual suggestion wrt module versioning.
>
[clipped rest - which is basically correct afaik (I don't know about
module versioning - but I made a userspace module-manager akin to the
kernel module manager as a bit of an exercise :]

> (4) The exporting object foo.c is compiled with -DEXPORT_SYMTAB which
> results in
> EXPORT_SMYBOL(bar);
> to expand into (cf. linux/modsetver.h, include/linux/module.h)
> const char __kstrtab_bar[]
> __attribute__((section(".kstrtab")))
> "bar_R123";
> const struct module_symbol
> __ksymtab_bar __attribute__((section("__ksymtab")))
> { (unsigned long)&bar, __kstrtab_bar };
> (As a side note: I can't figure out why the indirection __kstrtab_bar
> is needed. I think it would suffice to have
> const struct module_symbol __ksymtab_bar ...
> { (unsigned long)&bar, "bar_R123" };

this is because that symbol is exported to a seperate section of that file
(section "__ksymtab") (the name gets exported to ".kstrtab"). This is
where __start___ksymtab ends up pointing.

> (5) When the kernel image (vmlinux) is linked a standard ELF trick
> gathers all __ksymtab_* entries and uses them to populate
> the array __start___ksymtab. This array ends up as the `syms' field
> of the special struct module called `kernel_module'.
> (6) If insmod is asked to load quux.o it has to resolve all its unresolved
> references against the running kernel. insmod asks the kernel (using
> the system call query_module) for its "symbol table". This is an array
> of entries
> { address_of_symbol, "symbol_name_Rversion" }
> (You can see a human readable form of this "symbol table" by doing
> a cat on /proc/ksyms.) Turns out to that "symbol table" just is the
> array __start___ksymtab. insmod proceeds to look up the string "bar_R123",
> fetches the actual address of in the kernel and and patches the reference
> to `bar_R123' in quux.o accordingly.

The way symbols are extracted from a module and inserted into a running
kernel is by exporting the "__ksymtab" and ".kstrtab" sections of the
module into the kernel.... In other words, your "elf" trick you described
is already in use.

> (8) A very abstract way of saying the above is:
> - There is a database of
> exported symbol -> symbol version
> - This database is also present in the running kernel.
> - Every module object records the symbol version of each symbol
> that it imports (as it was at the time the module was built).

Yep - this is an automatic linker-thing. Modules are only partially
linked, and the linking is completed by "insmod". Sure wish I knew how to
override the import name though - I'd love to be able to export C++
classes.... (for my userspace thingy - C++ should not be in the kernel
imho... but that's purely imho and I remember still when C++ _WAS_ in the
kernel! :)

> - When loading a module we check the version recorded in the module
> against the running kernel's database.
> - If an exporting object changes we have to:
> - update the records for its exported functions in the database
> - update the records in all modules that import one of these functions

[clipped description of problem]
> OK, finally here's my SUGGESTION:
>
> Scrap the whole
> #define bar bar_R123
> stuff (and let quux.o reference `bar' as `bar' even in the module case).
> Instead record
> { "bar", 123 }
> in a special ELF section of an augmented form of quux.o

EXPORT_SYMBOL(sym, version) in effect. Wonder how to code that so
"version" is handled automatically? Be easy enough to change the module
format to handle this :)
[module format's changed several times in the 2.1 cycle]

> (let's call this quux.mod). modversions.h is replaced by
> modversions.o which is simply the (compiled) __ksymtab from above.
> Building quux.mod is as simple as
> ld -r -o quux.mod quux.o modversions.o -t some_loader_command_file

I just do "ld --retain-symbols-file $(TOP)/.symbols -o <module.o> -r
<dependencies.o>"
[which is what the kernel does :]

(and $(TOP)/.symbols contains "kernel_version", "init_module", and
"cleanup_module" (on seperate lines) - those being the only symbols the
module should export.

> This means that every module contains the whole symbol table (not only
> those symbols that it references). There is an obvious refinement
> to only include what's needed (perhaps this could be achieved by ELF
> magic?).

Already done :)

> Coming to think of it, if one also does the init_module and cleanup_module
> stuff correctly one might be able to use quux.mod also to link it into
> the kernel unchanged (the module specific sections will simply be stripped
> off when linking the kernel image).

The only problem with this is that you have to relocate the module so it's
compatible with kernel-space.... (open the destination memory, then
upload the module into that memory, then initialize). The current scheme
works better actually here.
(better == simple and easy to work with, although modutils is a bit tricky
to play with)

The userspace module-manager I built does all pretty much the same (I
built it to be as kernel-compatible as possible so I could experiment with
graphic device drivers :) The only real difference is that the userspace
manager loads its own modules.

G'day, eh? :)
- Teunis