开发者

dlsym()'ing a global variable in C++

开发者 https://www.devze.com 2023-02-20 19:29 出处:网络
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

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;
0

精彩评论

暂无评论...
验证码 换一张
取 消