View Single Post

   
  #1 (permalink)  
Old 01-04-2008, 09:07 PM
Ron
 
Posts: n/a
Default Creating C++ loadable modules for AIX: ANSWER

After much effort I was able to create C++ loadable modules for AIX
(using xlC). This is how it's done:

The problem:
We have a main program 'main' containing a class A with virtual
functions. We want to write a module 'module.so' to be loaded using
dlopen which will implement a class B, a subclass of A, which will
implement some or all of its virtual functions. Most importantly, the
module needs to access symbols from the main program.

The solution:
The solution is very straightforward on linux, but gave me some
trouble on AIX.
First of all, if we want the module to access main's symbols, we must
use the runtime linker. This is already enabled for the module if we
link with the -G flag, but we also need to enable it for the main
program using the -brtl flag.
By the way, enabling RTL on the main program when using g++ causes
dlopen to SIGSEGV. I don't know why.
Now, in AIX we need to explicitly export the symbols from the main
program.
!!! -bexpall WILL NOT WORK because (as the ld man page says) it does
not export symbols beginning with an underscore, as do all the symbols
representing operators, constructors and destructors in a C++ program.
Using -bexpall will probably cause dlopen to fail because the
runtime-linker will not be able to resolve all symbols.
So we must create an export file. This is simply done with the
CreateExportList utility which is given all of the main program's
objects, and creates an export file.

So we compile as follows:

main:
CreateExportList export_file $(objects)
xlC -Wl,brtl,-bE:export_file $(objects) -o main

module:
xlC -qmkshrobj -Wl,-G,-bnoentry module.C -o module.so

The -qmkshrobj flag is not always necessary - it does the same thing
CreateExportList does and passes the export list to the linker, but we
cannot use it for the main program as it also sets linker options
unique to shared objects. In any case, if we want to export all
symbols in the module we need to use it.

The rest is trivial:

module.c:

class B : public A {
...
}


extern "C" // this is necessary for dlsym to work
A *instance() { return new B; }

main.c:
...
void *handle = dlopen("module.so", RTLD_NOW | RTLD_GLOBAL);
A* (*instance)() = (A*(*)())dlsym(handle, "instance");
A *my_obj = instance();
Reply With Quote