I want to make a program which is able to dlo开发者_JAVA技巧pen()
a series of libraries (written by myself) and run all the functions stored in a global variable called test_suite
inside that .so file, which is a NULL-terminated array of function pointers (the functions' signatures are predefined by myself, no need to worry about that).
The problem is g++ mangles that variable. The library is compiled as:
g++ -Wall -shared -rdynamic -fPIC foo.cpp -o foo.so
and the "function index" is declared and allocated statically as:
const testunit_testcase test_suite = { ... }
yet
objdump -t foo.so | grep test_suite
shows:
0000000000200940 l O .data.rel.ro 0000000000000020 _ZL10test_suite
What I need is
0000000000200940 l O .data.rel.ro 0000000000000020 test_suite
So I can dlsym(dlh, "test_suite")
in the program dlopen()
'ing foo.so
Thanks
Addendum
Yes, extern "C"
was the first thing I've tried:
extern "C" {
const testunit_testcase test_suite[] = {
//TESTUNIT_DEF_TESTCASE(doTest),
{NULL, NULL},
};
}
I am using:
g++ -v Using built-in specs. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.2/lto-wrapper Target: x86_64-unknown-linux-gnu Configured with: /build/src/gcc-4.5-20110127/configure --prefix=/usr --enable-languages=c,c++,fortran,objc,obj-c++,ada --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-gnu-unique-object --enable-lto --enable-plugin --enable-gold --with-plugin-ld=ld.gold --disable-multilib --disable-libstdcxx-pch --with-system-zlib --with-ppl --with-cloog --with-cloog-include=/usr/include/cloog-ppl --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info Thread model: posix gcc version 4.5.2 20110127 (prerelease) (GCC)
Addendum 2
For whatever reasons
extern "C" {
const testunit_testcase test_suite = { ... }
}
does not work, BUT this one does:
extern "C" const testunit_testcase test_suite = { ... }
My question now: As I can see in some of your answers, enclosing extern "C" { ... }
works for you. Are there any compiler flags I could use to make sure that test_suite
will never be mangled, no matter what 4.x (at least) g++ version is used?
The problem isn't one of name mangling. (Or probably isn't: public variable names are not usually mangled.) The real problem is that the "const" means implicit static, rendering the variable invisible outside the translation unit. To avoid this, the variable must be explicitly declared extern. And "The form of linkage-specification that contains a brace-enclosed declaration-seq does not affect whether the contained declarations are definitions or not (3.1); the form of linkage-specification directly containing a single declaration is treated as an extern specifier (7.1.1) for the purpose of determining whether the contained declaration is a definition." Which, while it doesn't seem to address your issue directly (the presence of an initializer ensures that the declaration is a definition), it does seem to indicate the intent: within a brace enclosed linkage specifier, the usual rules apply; if the linkage specifier applies directly to the declaration, it's as if the declaration were explicitly extern. So you can write either:
extern "C" {
testunit_testcase const test_suite[] // ...
}
or
extern "C" testunit_testcase const test_suite[] // ...
But there must be an extern which applies explicitly to the definition, in order to override the implicit "static" of "const".
This
x.cxx:
extern "C"
{
extern const int test_suite[] = { 0 };
}
works for me:
~/ec% g++ -Wall -rdynamic -shared x.cxx -o x.so
~/ec% objdump -t x.so | grep test_suite
00000444 g O .rodata 00000004 test_suite
If I don't extern
test_suite
it doesn't get exported at all. This makes sense as const at file or namespace scope implies static
. It doesn't make sense because I would expect the extern "C"
block to "count" for that. I don't know if this is a gcc bug or not. Can you reduce your problem to something similar in size?
You're using a C++ compiler, so the name gets mangled. Try using either gcc
(if possible) or use
extern "C" {
const testunit_testcase test_suite = { ... }
}
The extern "C"
deactivates the name mangling.
Don't make that variable static
.
static
means that the variable is local to the current compilation unit, that's why g++ modifies its name. If you want the variable to be accessible "from the outside" you shouldn't make it static
. So, in the .cpp file, define the variable like this:
const testunit_testcase test_suite = { ... }
If you also declare the variable in a corresponding .h file, make that declaration extern
:
extern const testunit_testcase test_suite;
精彩评论