Jump to content

  • Log In with Google      Sign In   
  • Create Account


Can't resolve problematic dlopen() call.


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
15 replies to this topic

#1 taylorsnead   Members   -  Reputation: 139

Like
0Likes
Like

Posted 12 August 2012 - 08:01 PM

I've been working mainly in Windows with VC11, but a few days ago switched to using MinGW (I had already been planning on switching, I just liked Visual Studio's plugins too much). Very quickly, I then installed GCC/G++ 4.7 on my Linux (Mint). Making a launcher executable for my library (This makes it easier for separation, or changing which library is launched without recompiling a large amount of code), I use Boost.Extension's shared_library (which simply uses LoadLibrary and dlopen (depending on the platform)) to load my dynamic/shared library (SFGame.so). This worked great on windows with both compilers, but on Linux, dlopen will fail however I use the path. Using the same path, Boost.Filesystem confirms (through the application) that the file can be accessed with the paths I'm using. My simple code: ("<" and ">" replaced with "^")
[source lang="cpp"]#include "iostream"#include "functional"#include "boost/extension/shared_library.hpp"#include "boost/filesystem.hpp"#if _WIN32 || _WIN64# define EXT ".dll"#elif __APPLE__# define EXT ".dylib"#elif __linux# define EXT ".so"#endifint main( void ){ using namespace boost::extensions; using namespace boost::filesystem; std::string libpath = "./SFGame.so"; path pfile( libpath ); if( exists( pfile ) ) { std::cout ^^ "Game library: " ^^ complete( pfile ).generic_string() ^^ " exists\nSize: " ^^ file_size( pfile ) ^^ "\n"; } shared_library lib( libpath ); if( !lib.open() ) { std::cout ^^ "Failed to load " ^^ libpath ^^ "\n" ^^ dlerror() ^^ "\n"; return 0; } lib.get^void^( "Launch" )(); return 1;}[/source]
This same code works perfectly on Windows, as I said. My output:
../../BinLinux//SFGame.so: cannot open shared object library
or:
SFGame.so: cannot open shared object library
depending on whether I use "./SFGame.so" (I assume because my Code::Blocks project file and main.cpp are in "Engine/Code/Game/" and SFGame.so is in "Engine/BinLinux/") or "SFGame.so". I can use the full path from "complete(pfile).generic_string()", which gives the same dir in the error as "./SFGame.so". Any ideas on how I could fix this from failing EVERY time? I even tried linking Launcher to Engine.so in the compiler (GNU GCC (well, g++) within Code::Blocks), but no dice.

Edited by taylorsnead, 12 August 2012 - 08:04 PM.


Sponsor:

#2 Bregma   Crossbones+   -  Reputation: 4770

Like
0Likes
Like

Posted 12 August 2012 - 08:50 PM

Have you tried setting LD_LIBRARY_PATH to contain the directory containing the library (and removing the ./ in the library name)? The dynamic link interpreter (probably ld.so) has some rules about locating shared objects that are not the same as the rules the shell follows when launching executables.

If that fails, try using 'strace -e trace=open appname' when running your launcher to see exactly the paths the loader is actually trying to open.
Stephen M. Webb
Professional Free Software Developer

#3 taylorsnead   Members   -  Reputation: 139

Like
0Likes
Like

Posted 12 August 2012 - 09:13 PM

I should have mentioned that, yes, I already tried setting LD_LIBRARY_PATH, and that didn't help either. It seems that at compile-time, the string passing to the dlopen gets set to that path local to the main.cpp. strace shows that it is trying to open that directory, not just displaying it, whereas filesystem is really opening the correct directory (which I already knew since it showed it). I don't know how to get it using the correct path, unless I moved my source to the folder where it should compile, but that seems like a horrible solution.
EDIT: Or it has something to do with the "Execution Working Dir" Option in Code::Blocks. I've tried setting that relatively and absolutely to BinLinux, but no change.

Edited by taylorsnead, 12 August 2012 - 09:52 PM.


#4 sundersoft   Members   -  Reputation: 216

Like
0Likes
Like

Posted 12 August 2012 - 10:18 PM

I accidentally downvoted your post, sorry.

#5 e‍dd   Members   -  Reputation: 2105

Like
1Likes
Like

Posted 13 August 2012 - 06:41 PM

Perhaps it's worth removing the IDE from the equation for the time being. One you've built the host program and the .so, does it work (with or without LD_LIBRARY_PATH modifications) if you run it from a command shell?

If so, it may be the case that your IDE is setting the working directory inappropriately before exec()ing the process.

#6 taylorsnead   Members   -  Reputation: 139

Like
0Likes
Like

Posted 13 August 2012 - 07:50 PM

Okay, it seems like that was correct, though it seems that I do have to use an absolute path to the file, it works when compiled via terminal using g++-4.7, not using LD_LIBRARY_PATH (though I guess that would allow me to use relative paths). Code::Blocks still has the problem with the execution directory empty. Any thoughts on how to fix this? I guess I could just compile my Launcher with the terminal when I need to, but I'd prefer to be able to compile with my IDE (especially since it works fine on Windows, I feel like there should be an easy way to resolve this). It also seems like the same problem occurs with two dynamic libraries linked at compile/link time (of course, through Code::Blocks) (I use my Launcher as an executable to run my Game.so, which uses Engine.so to run and control the other, lower-level libraries (boost, glfw, alut, etc), so dynamic linking is important (though I use static linking when possible)).

#7 e‍dd   Members   -  Reputation: 2105

Like
1Likes
Like

Posted 14 August 2012 - 12:12 PM

Code::Blocks still has the problem with the execution directory empty. Any thoughts on how to fix this?


What do you mean by an empty execution directory? Whether you compile the your code from within your IDE or use the same commands from a shell, you should end up with an identical executable (except for internal timestamps, etc).

What is probable is that Code::Blocks has an option to specify the working directory for processes when you launch/debug them through the IDE. This would not be an option that effects the resulting binary in any way. So, just checking: do you understand the concept of a working directory (aka current directory aka current working directory :))?

#8 taylorsnead   Members   -  Reputation: 139

Like
0Likes
Like

Posted 14 August 2012 - 03:49 PM

Oh, I mean, Code::Blocks has an option for "Execution working dir", and I tried it empty, but the same problem occurred. Running the binary result either through the IDE or from the terminal makes no difference, unless I compile it via terminal. That is why the option seemed suspicious to me. Through this, I should think I do understand "working directory" as it would be used for file paths within the executable. Despite these, I don't know how the problem persists even using an absolute directory to the file, but I feel it's something with libdl.so, and less to do with working directory, but I have no idea what to do about it.

#9 Bregma   Crossbones+   -  Reputation: 4770

Like
0Likes
Like

Posted 14 August 2012 - 04:36 PM

I can pretty much guarantee that if there was such a glaring bug in dlopen() it would have been noticed and fixed some time in the last 20, 30, or 40 years. that should be a hint as to where the problem isn't.

Does strace show a fail when opening the shared object even when you use an absolute path? Are there additional symbols thatneed resolving in the dlopened object, and they're not getting resolved in the particular load set you're using from the IDE? Is there an architecture problem (you can not use 64-bit DSOs from a 32-bit app, and the reverse is usually problematic as well)?

Does it work properly if you set LD_PRELOAD to your DSO? Does setting LD_WARN spew warnings? Have you tried setting LD_DEBUG (hint: try LD_DEBUG=help first)?
Stephen M. Webb
Professional Free Software Developer

#10 taylorsnead   Members   -  Reputation: 139

Like
0Likes
Like

Posted 14 August 2012 - 04:53 PM

Now, using full strace (just "strace ./Launcher"), it seems that it detects the file correctly with an absolute path, but then it does a few things, and then it tries opening the file with some relative directory that wouldn't be correct anyways. This is the part of the output that applies:

brk(0) = 0x1310000
brk(0x1331000) = 0x1331000
open("/home/taylorsnead/Documents/ShadowFox/NewEngine/BinLinux/SFGame.so", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300!\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=27024, ...}) = 0
mmap(NULL, 2122168, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f8d2ab03000
mprotect(0x7f8d2ab09000, 2093056, PROT_NONE) = 0
mmap(0x7f8d2ad08000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x5000) = 0x7f8d2ad08000
close(3) = 0
open("../../BinLinux//SFEngine.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
munmap(0x7f8d2ab03000, 2122168) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8d2bcfe000
write(1, "Failed to load /home/taylorsnead"..., 82Failed to load /home/taylorsnead/Documents/ShadowFox/NewEngine/BinLinux/SFGame.so
) = 82
write(1, "../../BinLinux//SFEngine.so: can"..., 87../../BinLinux//SFEngine.so: cannot open shared object file: No such file or directory
) = 87

But, I don't know where it gets this new directory. Even using a relative directory, as with Boost.Filesystem, it sees the file, but dlopen (I guess) just converts it to a directory relative to the code/project files, which won't work with the executable. I'm using the same compiler for the libraries and executable, all (I guess, I don't specify to the compiler (G++)) 32-bit. Trying "LD_PRELOAD=SFGame.so /bin/ls" just says that SFGame.so can't be preloaded:
ERROR: ld.so: object 'SFGame.so' from LD_PRELOAD cannot be preloaded: ignored.
Using LD_PRELOAD with the path to Launcher instead of ls makes it run Launcher, which of course fails. Setting it without a path doesn't change the result of the strace of Launcher.

Edited by taylorsnead, 14 August 2012 - 05:02 PM.


#11 e‍dd   Members   -  Reputation: 2105

Like
1Likes
Like

Posted 15 August 2012 - 01:00 PM

Oh, I mean, Code::Blocks has an option for "Execution working dir" [...] Through this, I should think I do understand "working directory" as it would be used for file paths within the executable.

If I understand its purpose, this option should not affect the resulting executable. Rather, it will only affect the working directory with which the process is launched through the IDE. It is an option that affects running the compiled code, not compiling it in the first place.


Now, using full strace (just "strace ./Launcher"), it seems that it detects the file correctly with an absolute path, but then it does a few things, and then it tries opening the file with some relative directory that wouldn't be correct anyways.


That relative directory is likely the working directory. Again, are you sure you understand the concept?

Do "man getcwd" and use it to print the working directory at the start of your program. Does it match the directory in which your shared object resides?

#12 taylorsnead   Members   -  Reputation: 139

Like
0Likes
Like

Posted 15 August 2012 - 04:49 PM

getcwd(), in fact, does output the correct directory when launching from terminal and not the IDE (Which is what I do anyway).

#13 e‍dd   Members   -  Reputation: 2105

Like
0Likes
Like

Posted 16 August 2012 - 12:32 PM

So set the correct directory in the IDE...(?)

#14 taylorsnead   Members   -  Reputation: 139

Like
0Likes
Like

Posted 17 August 2012 - 05:55 PM

I had already done that with relative and absolute directories, the correct dir, and setting the dir to empty. Either way doesn't work.

#15 taylorsnead   Members   -  Reputation: 139

Like
0Likes
Like

Posted 19 August 2012 - 09:11 PM

Bump. Still not solved, and not sure how to attempt to.

#16 e‍dd   Members   -  Reputation: 2105

Like
0Likes
Like

Posted 21 August 2012 - 12:38 PM

Can you do a binary diff of the file built in the IDE against the file built in a command shell?

Have you tried examining the difference between the build commands when you build in the IDE vs in a command shell?




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS