design choices for a loadable module interface
Jeffrey Hutzelman
jhutz at cmu.edu
Thu Jun 3 04:38:25 EDT 2010
--On Tuesday, May 25, 2010 05:56:24 PM -0500 Nicolas Williams
<Nicolas.Williams at oracle.com> wrote:
> I strongly recommend against exported data symbols in an SPI.
Me too, mostly, though perhaps not for the same reasons. I might make an
exception for a simple type, such as an interface version number or a
string containing the module name, but it hardly seems worth the effort.
>> * exported function symbol(s)
>>
>> -- separate symbol for each interface function
>>
>> # Runtime symbol resolution can be slow on some platforms.
>
> But it's one-time. The framework should memoize the dlsym() calls.
Agree.
>> -- one function that returns a vtable, possibly parameterized by
>> version identifier
>>
>> # This may still require additional relocation overhead on some
>> platforms.
>
> The function pointers in the vtable should be pointers to either static
> or non-exported functions.
Generally, yes.
>> # Alternatively, have the function populate a passed-in
>> caller-allocated vtable, possibly with a sanity check on the
>> structure size. This can still cause additional relocations,
>> unless the function assigns the entries one at a time (e.g., by
>> doing arithmetic on PLT entries), instead of copying from a
>> prepopulated (private) struture.
>
> V-table versioning is needed in either approach.
>
> Either v-table scheme means having to Write More Code. Yuck, but I'd
> live.
I mostly dislike the vtable approach, regardless of the specific method of
finding it or who allocates the storage. Oddly, I'm fine with a model
where the library implements register_foo() functions that plugins can call
to register handlers/objects/whatever, even though those often include an
ops table in the registration data.
>> Should different modules that implement the same interface each export
>> a different name? If so, how would the caller discover the correct
>> name to pass to dlsym() or equivalent?
>
> IMO: yes, they should alluse the same symbol names.
Yes, absolutely, they should all use the same names. Architectures that do
otherwise are a major PITA in my opinion.
>> Relatedly, do we want to be able to use the same shared object as both
>> a loadable module and as a builtin?
>
> For static linking you should reduce the symbol scope to static and then
> resort to a vtable -- an internal dlsym(), effectively. This might
> require concatenating source files and using a C pre-processor symbol to
> expand to the keyword 'static'.
>
> Or you might:
>
>> Using different names per module might simplify linking the module as
>> a builtin, but the loader for builtin modules would still know how to
>> find it.
>
> use different names (possibly made to appear as the same in the source
> files by using auto-generated C pre-processor macros to rename the
> symbols to the plugin-specific names) and build your own internal
> dlsym() on top of that.
Yeah. Or do everything via published register_foo() interfaces, and have
each plugin publish an init function which is called when the plugin is
loaded, or at startup for built-in plugins. Of course the init functions
for builtins might have to have per-plugin names, in which case it'd be
relatively straightforward to generate a function which calls the init
functions of all the builtin plugins.
Or they could be static but included in some magic global table of init
functions to be called, possibly constructed by putting their addresses
into a separate ELF section, one address per plugin object, with the
startup code using the base address and length of that section to find the
table.
Oh dear; have I been staring at Linux too much? Sorry.
-- Jeff
More information about the krbdev
mailing list