C++ RTTI without libstdc++. Is it possible? - c++

I want investigate how is it possible to link C++ program without libstdc++, but with support of rtti. I tried compile it in the way described below. Any necessary but absent symbol I can define like function strcmp in the example, but is it possible to define typeinfo symbols without explicit mangle/demangle magic? And if possible how?
cd /tmp && cat << 'eof' >rtti.cpp && g++ -nodefaultlibs -lc rtti.cpp
extern "C" int strcmp(const char *s1, const char *s2) { return 0; };
#include "typeinfo"
int main(){
return typeid(int) == typeid(char);
}
Linker says:
/tmp/cc6rBAef.o: In function `main':
rtti.cpp:(.text+0x18): undefined reference to `typeinfo for char'
rtti.cpp:(.text+0x1d): undefined reference to `typeinfo for int'
collect2: error: ld returned 1 exit status
So, how can I define 'typeinfo of char'(_ZTIc##CXXABI_1.3) in source file using g++ or clang++?
PS. Don't ask me why do I need it. Just a curiosity.

Since the symbols needed for RTTI seem to be in the libstdc++ library, you cannot do completely without it. Note that I found this by running
readelf -Ws `g++ -print-file-name=libstdc++.so` | awk '{print $8}' | c++filt | grep 'typeinfo for'
What you can do, however, is statically link with libstdc++:
g++ -static-libstdc++ rtti.cpp
In this way, you won't have any dynamic dependencies on libstdc++ and only the symbols you actually need are pulled in to your executable. (Well, all symbols from the object file that contains the needed symbols, fundamental_type_info.o in you example, I suppose.)

Thanks to gcc community for hint.
The answer is:
"gcc use some magic to substitute destructor of __fundamental_type_info to a set of typeinfo symbols"
Substitution code is placed in file: gcc-4.7.2/gcc/cp/rtti.c, void emit_support_tinfos(void);
rtti.cc:
#include <typeinfo>
namespace __cxxabiv1 {
class __fundamental_type_info:public std::type_info{
public:
explicit __fundamental_type_info(const char* __n) : std::type_info(_n) { }
virtual ~__fundamental_type_info(){};
};
}
int main(){
return typeid(int) == typeid(char);
}
All fundamental typeinfos are inserted into object file during compilation.
$g++ -c ./rtti.cc;readelf -sW ./rtti.o |c++filt|grep typeinfo|wc -l
$153
So the question is answered.

Related

Why do I have an undefined reference error when linking for an object in the same archive?

I have a C++ source mycpp.cpp and a C source myc.c. The C source contains a function myCFunc(), which is called from the C++:
extern "C"
{
#include "my_c.h"
}
void aCppFunction()
{
myCFunc(stuff, and, things);
...
}
The two sources are compiled (to .o), and then archived (to .a), and then indexed, so no linking occurs:
ar qc thing.a *.o
ranlib thing.a
Later in the wider software build, this component archive is linked into a binary, and I get this error:
/usr/bin/ld: /path/to/mycpp.cpp:55: undefined reference to `myCFunc(unsigned char const*, unsigned int, unsigned int)'
I have extracted thing.a and can quite clearly see myc.c.o and mycpp.cpp.o, so I search them for the function:
> nm myc.c.o | grep myCFunc
00000000000001d0 T myCFunc
> nm -C mycpp.cpp.o | grep myCFunc
U myCFunc(unsigned char const*, unsigned int, unsigned int)
Can you see what is happening here? Why does the nm result for the C++ include the list of argument types, but the C result not? It seems to me that the function myCFunc() is defined in myc.c.o, which is part of thing.a along with mycpp.cpp.o, and that myCFunc's header is included correctly.
Please help!
The unlikely answer, based on j6t's invaluable comment:
Clearly, the caller of myCFunc does not see that name as extern "C", because the error message contains the parameter types. If it were seen as extern "C", the error message would only say undefined reference to myCFunc. – j6t
... is that what I did not show above, due to my C++ inexperience, is that the C header was included at the end of a train of other C++ headers, without using extern "C".

ldd does not show the dependency which make then needs

I have the program which needs v2xmvtest.so. When i try to build it via make i get undefined reference to *
Seems like that function from libssl1.0. (If i install it, it's built fine)
But i do not see the place where these function are used. More than that, when i try ldd v2xmvtest.so it does show only libvssl1.1 dependency.
Summary:
Is there a way to find out where those finctions from libvssl1.0 are used in the program ? (i have source code of the v2xmvtest.so and try to search, but there no any of these)
I need a description why ldd does not show me libssl1.0 dependency, but during linkning it's needed
Thank you!
Libraries are not required to fully define used symbols. For instance you can have lib.cpp:
int foo();
int bar(int x)
{
return x + foo();
}
and it compiles even foo is actually not defined yet:
g++ lib.cpp -shared -o lib.so
Then you can have main.cpp:
#include <iostream>
int bar(int);
int foo()
{
return 10;
}
int main()
{
std::cout << bar(42) << std::endl;
}
which defines foo and compiles successfully with lib.so:
g++ main.cpp lib.so -o main
The foo function in lib.so is expected just to be provided when the application is linked and is not specified where exactly from, even not necessary from a library.
You can check for undefined symbols in a library using nm tool:
nm -C -u lib.so
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U foo()
w __cxa_finalize##GLIBC_2.17
w __gmon_start__
And finally you can force gcc to ensure no undefined symbols are used by the object files by compiling with -Wl,-z,defs linker flag:
g++ lib.cpp -shared -Wl,-z,defs -o lib.so
...
lib.cpp:(.text+0x24): undefined reference to `foo()'

Error " undefined reference to `std::ios_base" while linking cpp header only library to fortran [duplicate]

This question already has an answer here:
Linking Fortran and C++ binaries using gcc
(1 answer)
Closed 3 years ago.
I am trying to link a header only library (which is in cpp) to a fortran code. I am using this example to test my library.
$ cat cppfunction.C
#include<cmath>
#include<mylib/mylib.hpp>
extern "C"
{
void cppfunction_(float *a, float *b);
}
void cppfunction_(float *a, float *b)
{
*a=7.0;
*b=9.0;
}
$ cat fprogram.f
program fprogram
real a,b
a=1.0
b=2.0
print*,"Before fortran function is called"
print*,'a=',a
print*,'b=',b
call cppfunction(a,b)
print*,"After cpp function is called"
print*,'a=',a
print*,'b=',b
stop
end
For compiling I am using:
$ gfortran -c fprogram.f
$ g++ -c cppfunction.C
$ gfortran -lc -o fprogram fprogram.o cppfunction.o
This runs fine if I remove my library header. But have this error when included:
cppfunction.o: In function `__static_initialization_and_destruction_0(int, int)':
cppfunction.C:(.text+0xa1): undefined reference to `std::ios_base::Init::Init()'
cppfunction.C:(.text+0xb0): undefined reference to `std::ios_base::Init::~Init()'
collect2: error: ld returned 1 exit status
Anything I might be doing wrong?
You're not linking the C++ standard library:
gfortran -lc -lstdc++ -o fprogram fprogram.o cppfunction.o
// ^^^^^^^^

test.c:(.text+0x36): undefined reference to `md5_file'

I installed polarssl:
make
sudo make install
tried to compile very simple file, named test.c:
#include <stdio.h>
#include "polarssl/md5.h"
int main(int argc, char * argv[])
{
int i;
for (i=1;i<1;i++)
{
char res[16];
if (md5_file("file.txt",res) == 0)
{
int count;
for (count=0;count<16;count++)
printf("%02x",res[count]);
printf("n");
}
}
return 0;
}
Compiled it like this:
gcc -lpolarssl test.c -I /usr/local/include/polarssl/
but it shows me:
/tmp/cczptlsk.o: In function `main':
test.c:(.text+0x36): undefined reference to `md5_file'
collect2: ld returned 1 exit status
whats the problem, how to fix it? I know for 100% that polarssl files are in /usr/local/include/polarssl/
The compiler will attempt to complete linkage in the order the objects or files are presented. In this case, since you had put -lpolarssl first, there were no unresolved symbols needed from that library, so nothing got linked in.
Putting -lpolarssl last lets the compiler resolve unresolved symbols from your source file from that library.
Includes are fine.
But linking is wrong. Try to put the -lpolarssl last in the linker command.
Then add a -L if libpolarssl.a is not found by the linker to point it to the right location.

g++ undefined reference to constructor

I'm compiling and linking a cpp file against a pre-compiled library, and I'm getting an "undefined reference" error.
Firstly, this is the command (the library in question is quicknet3, the program I'm compiling is trapper):
g++ -w -g -I. -g -O3 -pipe -Wall -I/home/install/x86_64/include/quicknet3 -L/home/install/x86_64/lib -lquicknet3 -lintvec -lfltvec -o trapper trapper.cpp CMyException.cpp
Here's the undefined reference error:
/tmp/ccFuVczF.o: In function 'main':
trapper.cpp:1731: undefined reference to 'QN_InFtrLabStream_PFile::QN_InFtrLabStream_PFile(int, char const*, _IO_FILE*, int)'
The call in trapper.cpp (line 1731) is:
IN_PFILE = new QN_InFtrLabStream_PFile(0, "", fp, 1);
where fp is a FILE *, assigned as the result of an fopen call beforehand.
The constructor being called is defined in the relevant header file (QN_Pfile.h), as follows:
class QN_InFtrLabStream_PFile : public
QN_InFtrLabStream
{
public:
QN_InFtrLabStream_PFile(int a_debug, const char* a_dbgname, FILE* a_file, int a_indexed);
(... other declarations ...)
}
The definition of the constructor is indeed given in QN_Pfile.cc:
QN_InFtrLabStream_PFile::QN_InFtrLabStream_PFile(int a_debug,const char* a_dbgname, FILE* a_file, int a_indexed) : log(a_debug, "QN_InFtrLabStream_PFile", a_dbgname),file(a_file),indexed(a_indexed),buffer(NULL),sentind(NULL)
{
(... the usual constructor stuff :P ...)
}
I compiled the quicknet3 library myself, without error, and installed it to /home/install/x86_64/lib/libquicknet3.a
So, I can't understand why the call from trapper.cpp is unable to find the reference to this constructor definition. The g++ arguments of -L/home/install/x86_64/lib -lquicknet3 should do the trick, right?
Any ideas?
Thanks,
Roy
I notice that you're mixing FILE* and _IO_FILE*. I'm not familiar with the latter, are you sure they're one and the same?
A quick workaround is to add /home/install/x86_64/lib/libquicknet3.a to g++ commandline.
I you want to investigate further, if g++ is picking another copy of libquicknet3, you can pass -v to g++ so it will output its searching paths.
FILE is a typedef of _IO_FILE. Your linker is treating it as a unique type.
You could try:
IN_PFILE = new QN_InFtrLabStream_PFile(0, "", (FILE *)fp, 1);
to see if this resolve your constructor.
(FILE is defined in stdio.h, _IO_FILE in libio.h if you're interested)