• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1886
  • Last Modified:

creating Linux shared object produces undefined symbols

I'm trying to use Java's JNA library to call c++ code and it doesn't seem to recognize the name of the function. What the Java JNA code needs is a shared object library of the c++ code.
 
There are only two files ClassMethodTest.cpp and the header file ClassMethodTest.h

I've been compiling the library two ways.
If I use gcc then I get the error

gcc -fPIC -g -c -Wall ClassMethodTest.cpp
gcc -shared -Wl -export-dynamic -o ClassMethodTest.so ClassMethodTest.o -lc

Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library '/root/projects/exampleSO/ClassMethodTest.so': /root/projects/exampleSO/ClassMethodTest.so: undefined symbol: __gxx_personality_v0


Viewing the shared object with command line command "nm" it shows that the symbol is U __gxx_personality_v0 is undefined


# nm -D ClassMethodTest.so
00001fe8 A __bss_start
         U __cxa_atexit
         w __cxa_finalize
00001ec0 A _DYNAMIC
00001fe8 A _edata
00001ff0 A _end
00000d28 T _fini
00001f98 A _GLOBAL_OFFSET_TABLE_
         w __gmon_start__
         U __gxx_personality_v0
00000844 T _init
         w _Jv_RegisterClasses
00000c16 T main
         U printf
         U _Unwind_Resume
         U _ZdlPv
00000b4e T _ZN15ClassMethodTest10getVersionEv
00000bfe T _ZN15ClassMethodTest11getVersion2Ev
00000b20 T _ZN15ClassMethodTest11printStringEPc
00000b1a T _ZN15ClassMethodTestC1Ev
00000b14 T _ZN15ClassMethodTestC2Ev
         U _ZNKSs4sizeEv
         U _ZNKSsixEj
         U _ZNSaIcEC1Ev
         U _ZNSaIcED1Ev
         U _ZNSsC1EPKcRKSaIcE
         U _ZNSt8ios_base4InitC1Ev
         U _ZNSt8ios_base4InitD1Ev
         U _Znwj
00000cd2 W _ZSt3minIjERKT_S2_S2_



If I use g++ the I get the error

g++ -fPIC -g -c -Wall ClassMethodTest.cpp
g++ -shared -Wl -export-dynamic -o ClassMethodTest.so ClassMethodTest.o

Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'printString': /root/projects/exampleSO/ClassMethodTest.so: undefined symbol: printString


Viewing the shared object with command line command "nm" it shows that the symbol printString is _ZN15ClassMethodTest11printStringEPc

if I use "_ZN15ClassMethodTest11printStringEPc" in the java code the function is called although with some irregularities

# nm -D ClassMethodTest.so
00001150 A __bss_start
         U __cxa_atexit
         w __cxa_finalize
00001018 A _DYNAMIC
00001150 A _edata
00001158 A _end
00000d88 T _fini
00001100 A _GLOBAL_OFFSET_TABLE_
         w __gmon_start__
         U __gxx_personality_v0
000008a4 T _init
         w _Jv_RegisterClasses
00000c76 T main
         U printf
         U _Unwind_Resume
         U _ZdlPv
00000bae T _ZN15ClassMethodTest10getVersionEv
00000c5e T _ZN15ClassMethodTest11getVersion2Ev
00000b80 T _ZN15ClassMethodTest11printStringEPc
00000b7a T _ZN15ClassMethodTestC1Ev
00000b74 T _ZN15ClassMethodTestC2Ev
         U _ZNKSs4sizeEv
         U _ZNKSsixEj
         U _ZNSaIcEC1Ev
         U _ZNSaIcED1Ev
         U _ZNSsC1EPKcRKSaIcE
         U _ZNSt8ios_base4InitC1Ev
         U _ZNSt8ios_base4InitD1Ev
         U _Znwj
00000d32 W _ZSt3minIjERKT_S2_S2_




The goal is to get either method to work, preferable gcc than g++, but anything that works will do.

From what I read about the situation I thought adding extern "C" to the header and the compile options used were supposed to make it so the function names don't get mangled.


#include <stdio.h>
#include "ClassMethodTest.h"


const char VERSION[]= "1.0";


ClassMethodTest::ClassMethodTest(){};
extern "C" {

void ClassMethodTest::printString(char *str){
  printf("Your String IS:%s\n",str);
}
}
std::string *ClassMethodTest::getVersion() {
	return new std::string(VERSION);
}

const char* ClassMethodTest::getVersion2(){
	return VERSION;
}

int main(){}



////////////////////////////////////////////////////Header

#ifndef __CLASS_METHOD_TEST
#define __CLASS_METHOD_TEST

#include <iostream>

extern "C" {


class ClassMethodTest{
 public:
  ClassMethodTest();
  void printString(char *str);
  static std::string *getVersion(); 
  const char* getVersion2();

};

}

#endif

Open in new window

0
mitchguy
Asked:
mitchguy
  • 4
1 Solution
 
Infinity08Commented:
>> /root/projects/exampleSO/ClassMethodTest.so: undefined symbol: __gxx_personality_v0

This is related to C++ exception handling, and is probably because you used gcc to link C++ code.

If your code is C++ code, then use g++, not gcc.

Or re-write the code to C code.


Regarding the name mangling - that's to be expected, since they are C++ functions. Name mangling is necessary due to the possibility of overloads, namespaces, etc.

The extern "C" is used when you want to link to C code (compiled with a C compiler). This is not the case here, so you don't need extern "C".
0
 
mitchguyAuthor Commented:
Ok so if I stick to C++ and now it's apparent that I must use g++. I had read that gcc uses g++ but that must have been bad information.

Is there any way to not have the name mangled

My little example is just to learn how to do things. The plan is to apply it to a much bigger project.
It's not feasible to look up the symbolic name for each function, I really need to be able to call the function
by its real name.
0
 
js-profiCommented:
don't think that java code could call c++ mangled names. don't think that java directly could use c++ classes or member functions. i think  you need c wrapper functions for entry to c++ with extern "C" . those could use c++ classes.
0
Nothing ever in the clear!

This technical paper will help you implement VMware’s VM encryption as well as implement Veeam encryption which together will achieve the nothing ever in the clear goal. If a bad guy steals VMs, backups or traffic they get nothing.

 
Infinity08Commented:
>> I had read that gcc uses g++ but that must have been bad information.

For compilation, it can derive that it needs to use the C++ compiler from the code file extension (.cpp). That doesn't work for the link command though.
To be safe, it's best to use the correct tool :)


>> Is there any way to not have the name mangled

In C++ ? No. As I said - it's necessary to support certain features of the language.


>> I really need to be able to call the function by its real name.

Take a look at JNI :

        http://en.wikipedia.org/wiki/Java_Native_Interface

It's pretty much the standard solution for calling native code from Java code and vice versa.
0
 
Infinity08Commented:
>> In C++ ? No. As I said - it's necessary to support certain features of the language.

Just to be complete : technically, you could, if you use normal global functions declared as extern "C". But not the way you tried it in your code.
0
 
Infinity08Commented:
Oh, and btw : C functions also use name mangling (adding an underscore before the name), just not the same kind of name mangling that C++ uses ;)
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now