Undefined symbol for dlsym in C++ [duplicate] - c++

This question already has answers here:
What is the effect of extern "C" in C++?
(17 answers)
Closed 3 years ago.
I have one C++ program which I want to load into my current running C++ program. Following are the snippet
File : a.cpp
#include<bits/stdc++.h>
using namespace std;
void abc() {
cout << "This is abc" << endl;
}
File : mainFile.cpp
#include <bits/stdc++.h>
#include <dlfcn.h>
int main(int argc, char **argv) {
system("g++ -fpic -shared -ldl -o a.so a.cpp");
void *lib = dlopen("./a.so", RTLD_NOW);
if (!lib) {
printf("dlopen failed: %s\n", dlerror());
return 1;
}
void (*f)();
f = (void (*)()) dlsym(lib, "abc");
if (f) {
f();
} else {
printf("dlsym for f1 failed: %s\n", dlerror());
}
dlclose(lib);
return 0;
}
I am compiling with the following commands
g++ -w mainFile.cpp -ldl -o mainFile && ./mainFile
Output:
dlsym for f1 failed: ./a.so: undefined symbol: abc
Please help.
I am compiling in Ubuntu 16.04 with g++ version g++ (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
OBSERVATION
What's strange is, when I have the above a.cpp file as a.c and with only stdio.h as header and also with a -fpermissive flag, the program compiles and I get the output as This is abc. I do not understand why the CPP version fails. The reason I cannot use CPP (or rather hesitate to go the .C route) is that my project requires OOPS concept and I have to use classes in the library file. The above example is only to simplify the objective.
Note: I have followed the following references but none helped.
Can you dynamically compile and link/load C code into a C program?
undefined reference to `dlopen' since ubuntu upgrade
C dlsym undefined symbol

In C++ names are mangled, that is, the name of the symbol in the library is not just abc. Instead it has additional characters (decoration) that describe the arguments etc. of that function. That is why you don't find the function by the name abc.
You have two options:
Look up the mangled name (which may be difficult/non-portable since mangling depends on the compiler).
Declare function abc() as extern "C" { void abc(); }. This requests C-linkage for the function and thus prevents name mangling.
See also the many pointers you got in the comments.

Related

dlopen succeeds (or at least seems to) but then dlsym fails to retrieve a symbol from a shared library

In an attempt to undersand how lazily loaded dynamic libraries work, I've made up the following (unfortunately non-working) example.
dynamic.hpp - Header of the library
#pragma once
void foo();
dynamic.cpp - Implementation of the library
#include "dynamic.hpp"
#include <iostream>
void foo() {
std::cout << "Hello world, dynamic library speaking" << std::endl;
}
main.cpp - main function that wants to use the library (edited from the snippet in this question)
#include <iostream>
#include <dlfcn.h>
#include "dynamic.hpp"
int main() {
void * lib = dlopen("./libdynamic.so", RTLD_LAZY);
if (!lib) {
std::cerr << "Error (when loading the lib): " << dlerror() << std::endl;
}
dlerror();
auto foo = dlsym(lib, "foo");
auto error = dlerror();
if (error) {
std::cerr << "Error (when loading the symbol `foo`): " << error << std::endl;
}
dlerror();
using Foo = void (*)();
(Foo(foo)());
}
Compilation and linking¹
# compile main.cpp
g++ -g -O0 -c main.cpp
# compile dynamic.cpp into shared library
g++ -fPIC -Wall -g -O0 -pedantic -shared -std=c++20 dynamic.cpp -o libdynamic.so
# link
g++ -Wall -g -pedantic -L. -ldynamic main.o -o main
Run
LD_LIBRARY_PATH='.' ./main
Error
Error (when loading the symbol `foo`): ./libdynamic.so: undefined symbol: foo
Segmentation fault (core dumped)
As far as I can tell, the error above clearly shows that the library is correctly loaded, but it's the retrieval of the symbol which fails for some reason.
(¹) A few options are redundant or, at least, not necessary. I don't think this really affects what's happening, but if you think so, I can try again with the options you suggest.
auto foo = dlsym(lib, "foo");
Perform the following simple thought experiment: in C++ you can have overloaded functions:
void foo();
void foo(int bar);
So, if your shared library has these two functions, which one would you expect to get from a simple "dlsym(lib, "foo")" and why that one, exactly?
If you ponder and wrap your brain around this simple question you will reach the inescapable conclusion that you must be missing something fundamental. And you are: name mangling.
The actual symbol names used for functions in C++ code are "mangled". That is, if you use objdump and/or nm tools to dump the actual symbols in the shared libraries you will see a bunch of convoluted symbols, with "foo" hiding somewhere in the middle of them.
The mangling is used to encode the "signature" of a function: its name and the type of its parameters, so that different overloads of "foo" produce distinct and unique symbol names.
You need to feed the mangled name into dlsym in order to resolve the symbol.

Calling C code from C++ with using extern "C"

I have 3 files with me, one c++ file, main.cpp, one c file, test.c and one header file, test.h
I wanted to try and use C code into C++ file. For the same reason, I have declared an function in test.h and defined that in test.c and using that in main.cpp
main_temp.c is just for explanation.
test.h
void test(int);
test.c
#include <stdio.h>
void test(int a) {
printf("%d", a);
main_temp.cpp
#include "test.h"
int main() {
foo(5);
}
Here, I understand why this would not work. C symbol would be simple 'foo' but since C++ does more things while creating symbols, it might be 'void#test(int)' and to solve this name mangling problem, I have to treat C++ symbol as a C symbol. So, I would use extern "C" and my main.cpp becomes as like:
main.cpp
extern "C" {
#include "test.h"
}
int main() {
foo(5);
}
I could not understand as to why this would not work! I get :
main.cpp:(.text+0xa): undefined reference to `test`
Can somebody share the insights?
I trust you compile or link them together? Else that would be the cause. On gcc it would be something like:
g++ -c -o main.o main.cpp
gcc -c -o test.o test.c
g++ -o a.out main.o test.o
Assuming you have no bugs with compiling/linking, compile both main.cpp and test.c into object files and run nm on both. It will show what symbol main.o wants and what symbol test.o exports. It should become clear then why linker cannot do its job.

Linking Error due to symbol(s) not found in Bjarne Stroustrup "Programming and Practices using c++"

I'm new to c++ (and compiled languages in general) and am doing the drill at the end of chapter 8 in Bjarne Stroustrup "Programming and Practices using c++" but I'm getting the following error when I try to compile the code
➜ Desktop g++ -std=c++11 *.cpp -o use
Undefined symbols for architecture x86_64:
"_foo", referenced from:
print_foo() in my-4f7853.o
_main in use-46cb26.o
(maybe you meant: __Z9print_foov)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I've also tried using g++ -c my.cpp use.cpp followed by g++ -o use.exe my.o use.o but this gave the same error. The other approach I tried was g++ -c use.cpp -o use.exe, however use.exe produced no output when it ran. The source code files are
my.h
extern int foo;
void print_foo();
void print_int(int);
my.cpp
#include "my.h"
#include <iostream>
void print_foo() {
std::cout << foo << '\n';
}
void print_int(int num) {
std::cout << num << '\n';
}
use.cpp
#include "my.h"
#include <iostream>
int main() {
std::cout<<"DSGFSGFSG"<< '\n';
foo = 7;
print_foo();
int i = 99;
print_int(i);
}
I've looked at other questions that are similar (if not seemingly the same is in Link-time errors in VS 2013 while compiling the C++ program - B. Stroustrup's PPP using C++: Ch. 8 - Q1 Drill?) but the solutions haven't worked for me. Is the problem to do with my compilation using g++ or have I made a more fundamental error?
The global variable foo is only declared in your header file.
extern int foo;
You also need to define it in my.cpp
int foo;
The declaration is a promise: "it exists somewhere".
The definition actually reserves some storage for this variable.
So your linker complains because some code relying on this
promise needs to access this missing storage.

Cygwin linking shared library

UPDATE:
Removed old question about .so files. They aren't intended to work on Windows.
I solved the below using a header file. I am guessing it is a standard convention to use .h file every time you link using C++?
mydll.h:
#ifndef mydll_h_
#define mydll_h_
void hello();
#endif
myprog.cc:
#include "mydll.h"
int main ()
{
hello ();
return 0;
}
mydll.cc:
#include <iostream>
void hello()
{
std::cout << "Hello World!\n";
}
Alternatively, I tried .dll library using Cygwin with this guide: https://cygwin.com/cygwin-ug-net/dll.html
The compilation for their .c files work, but I am trying to get it to work for my .cc files. Any ideas?
mydll.cc:
#include <iostream>
void hello()
{
std::cout << "Hello World!\n";
}
myprog.cc:
int main ()
{
hello ();
return 0;
}
I typed:
g++ -c mydll.cc
g++ -shared -o mydll.dll mydll.o
But when I type:
g++ -o myprog myprog.cc -L./ -lmydll
I get:
myprog.cc: In function ‘int main()’:
myprog.cc:4:10: error: ‘hello’ was not declared in this scope
hello ();
You're facing a compiler problem; not a linker problem. The compiler is telling you that when it compiles myprog.cc, it can't find function hello().
You need to write a function declaration for hello(). Note: you're function definition for hello() is in mydll.cc.
A function declaration would simply be:
void hello();
(1) You could place this one line of code in your myprog.cc above int main().
(2) You could also place this one line of code in a header file that is included at least by myprog.cc and optionally by mydll.cc. But good programming practice dictates that the header file should be included by both.
If you follow option 1, the following version of myprog.cc will fix your compiler error:
void hello(); // "extern void hello();" would be more proper.
int main ()
{
hello ();
return 0;
}
Option 2 would entail:
myprog.cc:
#include <mydll.h>
int main ()
{
hello ();
return 0;
}
Either way results in successful compilation and execution:
>g++ -c mydll.cc
>g++ -shared -o mydll.dll mydll.o
>g++ -o myprog myprog.cc -L./ -lmydll
>./myprog.exe
Hello World!
>

g++ linking against static library [duplicate]

This question already has answers here:
"undefined reference" when linking against a static library
(4 answers)
Closed 8 years ago.
my main.cpp:
#include <iostream>
int foo(int arg);
using namespace std;
int main()
{
int x = foo(22);
cout << x;
return 0;
}
compile command line (Ubuntu 13.10):
g++-4.8 -L. -lfoo main.cpp -o main_app
libfoo.a contains int foo(int)
but I always get the same compiler error:
/tmp/cciAyTSP.o: In function `main':
main.cpp:(.text+0x19): undefined reference to `foo(int)'
collect2: error: ld returned 1 exit status
Of course it's impossible to be sure without a reproducible case, but a common error is that if the function foo is written in C then you need to put
extern "C" { int foo(int); }
in the .h file for the C++ program to let it know that the function was not written in C++.
To write a cross-language header file that will be good for both C and C++ the common approach is
#ifdef __cplusplus
extern "C" {
#endif
... C declarations ...
#ifdef __cplusplus
}
#endif
In addition to 6502's answer and Xephon's suggestion, also be aware that the order of the options matter. Instead of:
g++-4.8 -L. -lfoo main.cpp -o main_app
You should write:
g++-4.8 main.cpp -o main_app -L. -lfoo
That's because ld is a single pass linker. It won't revisit library libfoo to use a symbol from it for main_app.o.