J.D. Koftinoff Software, ltd.
ELF Plugins for Linux in C++
Dynamically Loaded C++/ELF Plugins for LINUX
Nov 24 1995
By Jeff Koftinoff, jeffk@jdkoftinoff.com
http://www.jdkoftinoff.com/
Referenced by the paper "Design Patterns for Derivatives Software" by Maarten van der Meij1, Diederik Schouten1, and Anton Eliens
Released in November 2008 under the GPLv2 or later
Please see the file COPYING for license information.
You can download the package jdkelf.tar.gz here.
- OVERVIEW -
Ok, here is an example C++ program that can exploit the cool things that
we can do with ELF. With a system like this, you can dynamically extend
a c++ program with new sub-classes after the program has been compiled,
and without having to re-compile the program.
I am using GCC 2.7.1, libc.so.5.2.10, libdl.so.1.7.9, ld.so.1.7.9, libg++.so.27.0.2
and libstd++.so.27.0.2
It will work with GCC 2.7.0 and with older libc.so. libg++ and libstd++
seem crucial to RTTI and I haven't yet figured out what to do to compile
a shared library version of libg++-2.7.1
The example code uses the C++ headers <typeinfo> <iostream.h>
and <string>. if your system isn't working with typeinfo yet you can
modify world.h and the test files to not use RTTI.
Take a look at dll.h and plugin.h. This stuff is really quite straightforward.
- COMPILING AND RUNNING -
To compile, run 'make'. It will make the executable "plugtest" as well
as the two plug in libraries "PlugInFun.so" and "PlugInHappy.so"
To run the test program, type "./plugtest"
It will ask you for a name of a dll. You may give the full path name
of one of the previously made plug in libraires. If you want, you can
export LD_LIBRARY_PATH=".:$LD_LIBRARY_PATH"
This will allow you to enter in the file name of the plug in library you
want without the full path name. Probably it is best to give the full path
name or put your plugins in a special place.
Once you give it a valid name, it will attempt to open that library
file and create an object from the class defined within. It will then call
the Show() method of that object, and then will display the C++ RTTI typeid
name. After all this it will destroy all the objects created.
- GUIDELINES -
The key for this whole system to work is to:
-
Have good abstract base classes/factory classes in your application for
the libraries to inherit from
-
compile everything with "-fPIC"
-
link the executable with the "-rdynamic" flag and the dl library
-
create the shared libraries with the "-shared" flag
-
be wary of RTTI and exception handling - newer versions of compilers may
do internal things differently and cause big problems if you compile your
application with one version and the shared libraries with another.
- PROBLEMS -
Here are some problems I encountered:
-
If you try to open an object file as a library, it looks like libdl prints
an error message to stderr. I don't think it should do this - It should
just return the appropriate error code.
-
Stay away from global/static objects that require constructors in your
library code. It looks like they will be called, but you are probably asking
for trouble, especially when exceptions come on to the scene.
-
Make SURE your abstract base classes are good enough to not need changing.
If you have to change a base class, then the main application needs re-compiling.
-
I may be missing a link flag somewhere - If I take out all iostream, string,
and rtti calls from the main program, and don't call 'new' from the main
program either, I get an error when linking in my library that needs '__builtin_new'
which is not in the main application.
-
I also noticed that RTTI in the library doesn't seem to work properly if
the main application doesn't directly require it. I suspect that the libstd++
RTTI initialization code is not being executed at program startup because
it appears the program doesn't need it, which is wrong.
-
There must be a way to either force it to be linked into the main app (instead
of being implicit) or to be able to link it directly from libg++/libstd++
to the library.
-
Right now the plug-ins and the executable seem really too big, even stripped.
My problem could be that the linker is statically linking libstd++ and/or
libg++ into the libraries and executable.
-
Does the application really have to be compiled with -fPIC ?
If you find any info regarding these problems, please drop me a line!
- FIXED Things -
News flash! Silly me- Many of the previous 'Problems' were my fault!
-
I was trying to upgrade to libg++2.7.1, which wasn't working, and was causing
the linker to statically link in iostream into each library.
-
Once I went back to libg++2.7.0.2 everything seems to work fine.
-
My test program that didn't use iostream and failed with RTTI typeid(*c).name
was my fault, not the compiler - printf() accepts typeid(*c).name when
it should have been typeid(*c).name().
I still have the problem with ld.so outputting errors via stderr when I
don't want it to.
- FILES -
Files included here:
Makefile:
The Makefile
world.h:
common include file for everything
plugtest.cc:
main program to test plugins
dll.h and dll.cc:
Defines the DLLManager, DLLFactoryBase, and DLLFactory<T> classes
plugin.h:
Abstract base classes for PlugIn and PlugInFactory
PlugInHappy.cc:
A plug in class and factory, called "PlugInHappy"
and "PlugInHappyFactory". Used to make PlugInHappy.so
PlugInFun.cc
A plug in class and factory, called "PlugInFun"
and "PlugInFunFactory". Used to make PlugInFun.so