I have a lot of code that was written on 32 bit machine. Now I've upgraded to 64 bit, and it won't load shared objects. The shared object is compiled for 32 bit (using -m32 flag for DMD), and so is the host application.
This is the shared library:
module lib;
export extern(C) int abcd(){
return 4;
}
it is compiled using dmd -shared -m32 lib.d, and the output is lib.so
And this is the code for the loader:
module loader;
import std.stdio;
import core.sys.posix.dlfcn;
alias func = extern(C) int function();
void main(string[] args){
writeln("reached 0, press enter");readln;
void* so = dlopen("/home/nafees/Desktop/temp/lib.so",RTLD_LAZY);
writeln("reached 1, press enter");readln;
func f = cast(func)dlsym(so,"abcd");
writeln((*f)());
}
This one is compiled using dmd -m32 loader.d. It compiles fine, but when I run it, it runs fine till the dlopen, then causes a segmentation fault(core dumped). This used to work fine on 32 bit.
What is wrong in this code, why won't it work?
P.S: I don't want to compile it for 64 bit, so if a solution requires removing -m32, I need another one.
EDIT: I have a program compiled (also written in D), that loads a shared object (which is also written in D), using dlopen. That program would run fine in 32 bit, but not on my 64 bit machine.
EDIT2: I now tried compiling the loader without -m32, it now dlerror is saying this: /home/nafees/Desktop/temp/lib.so: wrong ELF class: ELFCLASS32
Instead of dlopen try to use loadLibrary.
UPDATE:
Use -fPIC flags for compile lib.d:
dmd -m32 -fPIC -shared lib.d
Related
Background
I have read countless GitHub project threads and everything I can find on StackOverflow about this problem, though so far no luck. I have a Mac 10.14 box running with the stock CommandLineTools and/or Xcode. I'm trying to "port" a Python wrapper library I have written around an older C and C++ library using CTypes in Python3. It works well already on Ubuntu Linux. However, there is no end to the problems I have been coming across since moving to a Mac platform. There just doesn't seem to be an easy answer to fixing what I'm trying to do on the broken Mac OS platform right now -- at least for the uninitiated Linux person like myself.
I have one question right off the bat before I describe how I'm compiling the dylib I'm trying to load up with CTypes: Do I now need to sign my dylib somehow before I can use it on Mac 10.14? Otherwise, I guess my question boils down to how the $%^# (and that is truncated speak for what I do mean right now) can I deal with shared / dynamic libraries on Mac with a Python C extension interface?
My preference is to not even touch Xcode and just use the stock Mac tools that come with the system out of the box. My solution must work on the command line without defering to some auto configuration magic that Xcode will give you in GUI form. Really, this is all fairly painless for what it is under Linux.
Compilation and linking
The scenario is actually more complicated than I can describe. I will just sketch what seems to me to be the relevant parts of the solution, and then let you all experts who have gotten this working before tell me the obvious missteps in between.
I'm compiling the older C/C++ source code library as a static archive first using the following
gcc (read clang) options on Mac (some of them get ignored):
-O0 -march=native -force_cpusubtype_ALL -fPIC -I../include -fPIC -m64 \
-fvisibility=default -Wno-error -lc++ -lc++abi
Then I'm compiling and linking with a combination of
-Wl,-all_load $(LIBGOMPSTATIC).a $(LIBGMPSTATIC) -Wl,-noall_load \
-ldl -lpthread -lc++ -lc++abi
and
-dynamiclib -install_name $(MODULENAME) \
-current_version 1.0.0 -compatibility_version 1.0
to generate the dylib output.
For comparison, on Linux, the analogs to these flags that work are approximately
-Wl,-export-dynamic -Wl,--no-undefined -shared -fPIC \
-fvisibility=default -Wl,-Bsymbolic
-Wl,-Bstatic -Wl,--whole-archive $(LIBGOMPSTATIC).a $(LIBGMPSTATIC) -Wl,--no-whole-archive \
-Wl,-Bdynamic -Wl,--no-as-needed -ldl -lpthread
and
-Wl,-soname,$(MODULENAME)
The dylib output
The above procedure gives me a dylib file that I can scan with nm to see the symbols I am trying to import with CTypes. This is a good start. When I try to run the test python script to test my CTypes wrapper library, I get a SEGFAULT immediately. Since gdb is apparently useless on Mac these days (sorry), I used the stock llvm to load up a brew-installed python3 with extra debugging symbols:
lldb /usr/local/Cellar/python-dbg\#3.7/3.7.6_13/bin/python3
(lldb) run myscript.py
Process 75435 launched: '/usr/local/Cellar/python-dbg#3.7/3.7.6_13/bin/python3' (x86_64)
Process 75435 stopped
* thread #2, stop reason = exec
frame #0: 0x0000000100005000 dyld`_dyld_start
dyld`_dyld_start:
-> 0x100005000 <+0>: popq %rdi
0x100005001 <+1>: pushq $0x0
0x100005003 <+3>: movq %rsp, %rbp
0x100005006 <+6>: andq $-0x10, %rsp
Target 0: (Python) stopped.
(lldb) bt
* thread #2, stop reason = exec
* frame #0: 0x0000000100005000 dyld`_dyld_start
(lldb) c
... redacted path information ...
File "/usr/local/Cellar/python-dbg#3.7/3.7.6_13/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ctypes/__init__.py", line 442, in LoadLibrary
return self._dlltype(name)
File "/usr/local/Cellar/python-dbg#3.7/3.7.6_13/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ctypes/__init__.py", line 364, in __init__
self._handle = _dlopen(self._name, mode)
OSError: dlopen(GTFoldPython.dylib, 6): image not found
Process 75435 exited with status = 1 (0x00000001)
I do have each of the environment variables PYTHONAPPSDIR=/usr/local/Cellar/python-dbg#3.7/3.7.6_13, PYTHONPATH, LD_LIBRARY_PATH, DYLD_LIBRARY_PATH set to correct paths.
So the question is what do I try next to get this working? Many, many hours of thanks in advance!
In my case, the issue turned out to be two things.
The first is that I was running my python script with a different version of python than the C extensions were linked with. For example, the following is the output of my python3-config --ldflags command:
-L/usr/local/Cellar/python-dbg#3.7/3.7.6_13/Frameworks/Python.framework/Versions/3.7/lib/python3.7/config-3.7dm-darwin -lpython3.7dm -ldl -framework CoreFoundation
So running it with /usr/local/Cellar/python-dbg#3.7/3.7.6_13/bin/python3 caused errors for me. This can be resolved by running the script with /usr/local/Cellar/python-dbg#3.7/3.7.6_13/bin/python3.7dm. Not an obvious fix given that brew installs each with an only slightly modified tap formula.
Second, in my C code, I am frequently writing to an extern'ed character buffer that lives on the stack. When this happens, the default clang stack protection mechanisms throw a SIGABRT at the script. To avoid this, you can recompile by passing the following flags to both the compiler and linker (might be more disabling than is actually needed):
-fno-stack-check -fno-stack-protector -no-pie -D_FORTIFY_SOURCE=0
With these two fixes in place my script runs. And still crashes for other reasons related to multithreading with Python in C. However, this is to be expected, but still has yet to show up in my testing on Linux.
Thanks to #l'L'l for helping me to work through this.
If I define a symbol address when linking a program on Ubuntu 16.10, this doesn't seem to produce the correct address when running the program. For example taking the following program
#include <stdio.h>
extern int mem_;
int main()
{
printf("%p\n", &mem_);
}
and compiling with
gcc example.c -o example -Xlinker --defsym=mem_=0x80
then running the program prints 0x80 on older Ubuntu systems, but a random number on Ubuntu 16.10. The 0x80 symbol seems to go into the executable, as shown by the nm program, however.
Any ideas what's causing this? I'm suspecting a security feature.
Under the GCC section of the ChangeLog (found here: https://wiki.ubuntu.com/YakketyYak/ReleaseNotes)
"We have modified GCC to by-default compile programs with position independent executable support, on the amd64 and ppc64el architectures, to improve the security benefits provided by Address Space Layout Randomization."
To disable this option, simply add -no-pie to GCC's flags.
The Scenario
I am developing an application in C99 ANSI C that uses OpenMP and GMP. It's natural habitat will be a linux machine with plenty of cores, so there's basically no big trouble there, but for reasons I do not want to debate here, I have to develop under Cygwin on a 64 bit Windows machine.
When I use the 32 bit version of gcc, something, somewhere, goes horribly wrong and the application is about 60 times slower than a very crude single-threaded version, when it should in fact be faster by a factor that equals the number of CPU's. It makes it impossible to work with. I really don't know what is causing this; Anyway, I have decided to use the 64 bit version of MinGW instead, that'd be x86_64-w64-mingw32-gcc-4.5.3 and his friends, to be precise.
A side note: I am sure that the slowdown is not a flaw in my multithreading, the multithreaded application works correctly and faster on the linux machine.
The actual Problem
Setting up GMP was easy, it can be compiled from source without any trouble and then works like a charm. Compiling the following easy example with -fopenmp also works like a charm:
#include <gmp.h>
#include <omp.h>
int main() {
#pragma omp parallel
{
mpz_t t;
mpz_init(t);
mpz_set_si(t,omp_get_thread_num());
# pragma omp critical
{
gmp_printf("Hello From GMP'd Thread %Zd!\n",t);
fflush(stdout);
}
mpz_clear(t);
}
return 0;
}
However, executing it gives me
$ ./test
test.exe: error while loading shared libraries: ?:
cannot open shared object file: No such file or directory
I am aware of this question, but I would like to make this work without downloading any binaries other than those from an official Cygwin repository. Since my example compiled with the -fopenmp switch, I am convinced that this should also be very much possible.
Can someone help me with that? Thanks a bunch in advance.
I think that "error while loading shared libraries: ?:" means that cygwin does not know where to find libgmp-10.dll and/or libgomp-1.dll.
Both DLL are required according to Dependency Walker
Your program worked after I added the directory that contains both DLL to my PATH:
#$ x86_64-w64-mingw32-g++ -fopenmp -o w64test gmp_hello.c -lgmp
#$ file ./w64test.exe
./w64test.exe: PE32+ executable (console) x86-64, for MS Windows
#$ ./w64test.exe
/home/david/SO/hello_openmp/w64test.exe: error while loading shared
libraries: ?: cannot open shared object file: No such file or
directory
#$ ls /cygdrive/c/dev/cygwin/usr/x86_64-w64-mingw32/sys-root/mingw/bin/*mp*dll
/cygdrive/c/dev/cygwin/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libgmp-10.dll
/cygdrive/c/dev/cygwin/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libgomp-1.dll
#$ export PATH=$PATH:/cygdrive/c/dev/cygwin/usr/x86_64-w64-mingw32/sys-root/mingw/bin/
#$ ./w64test.exe
Hello From GMP'd Thread 1!
Hello From GMP'd Thread 0!
note
I compiled and installed gmp-5.0.5 with the following commands:
./configure --build=i686-pc-cygwin --host=x86_64-w64-mingw32 --prefix=/usr/x86_64-w64-mingw32/sys-root/mingw --enable-shared --disable-static
make -j 2
make check
make install
update
Your program also works with cygwin "GCC Release series 4 compiler".
#$ g++ -fopenmp -o cygtest gmp_hello.c -lgmp
#$ ./cygtest.exe
Hello From GMP'd Thread 1!
Hello From GMP'd Thread 0!
#$ g++ -v
Target: i686-pc-cygwin
Thread model: posix
gcc version 4.5.3 (GCC)
You might need to install the following packages:
libgmp-devel (Development library for GMP)
libgmp3 (Runtime library for GMP)
libgomp1 (GOMP shared runtime)
I've seen this question on here, tried the proposed fixes, but no success so far for me. I have quite some Java experience, but JNI is a long time ago, never did it on Linux though...
I'm trying to get a simple HelloWorld JNI app running on Linux.
Small java file:
class HelloWorld {
private native void print();
public static void main(String[] args){
new HelloWorld().print();
}
static {
System.out.println(System.getProperty("java.library.path"));
System.loadLibrary("HelloWorld");
}
}
Small C file:
#include <jni.h>
#include <stdio.h>
#include "HelloWorld.h"
JNIEXPORT void JNICALL
Java_HelloWorld_print(JNIEnv *env, jobject obj)
{
printf("Hello World!\n");
return;
}
compiled the C file by:
gcc -shared -Wall -fPIC HelloWorld.c -I/usr/lib/gcc/x86_64-redhat-linux/3.4.3/include/ -o libHelloWorld.so
Run the app by:
java HelloWorld
or
java -Djava.library.path=/home/nxp40954/jnitesting/. HelloWorld
But no good, getting a:
Exception in thread "main" java.lang.UnsatisfiedLinkError: /home/nxp40954/jnitesting/libHelloWorld.so: /home/nxp40954/jnitesting/libHelloWorld.so: cannot open shared object file: No such file or directory
Strange, because there is actually a /home/nxp40954/jnitesting/libHelloWorld.so file.
Does anyone have a clue?
execute this way:
export LD_LIBRARY_PATH=.
java HelloWorld
The java.lang.UnsatisfiedLinkError is thrown when the .so file cannot be loaded.
The LD_LIBRARY_PATH variable points extra location to look for the *.so files.
I'm on 32bit ubuntu with sun java. I was compiling this way:
gcc -shared -Wall -fPIC HelloWorld.c -I/usr/lib/jvm/java-6-sun-1.6.0.26/include -I/usr/lib/jvm/java-6-sun-1.6.0.26/include/linux -o libHelloWorld.so
Your example worked for me on a 32-bit Linux installation.
Is your shared library compiled as a 32-bit or 64-bit shared library? Check with command file libHelloWorld.so. If your shared library is 64-bit then you need to give command line option -d64 when starting Java so that Java can load the 64-bit shared library.
If your shared library is 32-bit then perhaps the Java option -d32 will solve the problem.
Clarification on java.library.path and system path:
java.library.path is a JVM-Variable which can be set - e.g. - by the command line parameter
-Djava.library.path=xy
DLL's (on windows) and so's (on linux) which are loaded by the java call loadLibrary() must be located in the java.library.path. If it is loaded via JNI it must be located in the system path.
If such a linked library loads another linked library, latter must be found in the system path. In Windows the system path is resolved against the PATH environment variable, in linux it's the LD_LIBRARY_PATH environment variable (for linked libraries).
Another point to ensure in linux: Verify that the linked library has executable permissions for the current user. Usually a
sudo chmod 755 myLinkedLib
does the trick.
I have a piece of C/C++ code that uses __thread keyword for thread local storage but having trouble getting it compiled on 64-bit Solaris Sparc with g++ (version 4.0.2), while it compiles and runs OK on linux with g++34 compiler. Here is an example of source code:
__thread int count = 0;
Compiler info from 'g++ -dumpversion' command returns '4.0.2' and 'g++ -dumpmachine' shows 'sparc-sun-solaris2.8'. 'uname -a' displays 'SunOS devsol1 5.9 Generic_118558-26 sun4u sparc SUNW,UltraAX-i2'.
The error message while running make with g++ is: "error: thread-local storage not supported for this target", and compiler option I am using is
-m64 -g -fexceptions -fPIC -I../fincad -I/usr/java_1.6.0_12/include -I/usr/java_1.6.0_12/include/solaris -I/opt/csw/gcc4/lib/sparcv9 -I/opt/csw/gcc4/lib/gcc/sparc-sun-solaris2.8/4.0.2/sparcv9 -I. -I/usr/include -I/usr/include/iso -I/usr/local/include
Any help is very much appreciated as I have being struggling on this over the weekend and am facing a deadline.
Thanks,
Charles
You can ignore the gcc-specific thread-specific storage and use posix thead-specific storage. It should work and it's not gnu-specific. There's an example on the
sun site.
Here's a condensed example from ibm. Obviously you'd want to use more than one thread.
pthread_key_t tlsKey = 0;
int main(int argc, char **argv)
rc = pthread_key_create(&tlsKey, globalDestructor);
/* The key can now be used from all threads */
// Each thread can now use the key:
char *myThreadDataStructure;
void *global;
myThreadDataStructure = malloc(15);//your data structure
pthread_setspecific(tlsKey, myThreadDataStructure);
/* Get the data back */
global = pthread_getspecific(tlsKey);
free (myThreadDataStructure);
rc = pthread_key_delete(tlsKey);
}
You can try adding the -pthread command-line option to g++: this options means, in GCC parlance: "do everything required for POSIX threading support". This might unlock support for __thread.
Thread-local storage with __thread requires some specific system support, in the compiler but also in the linkers (both the static linker, invoked at the end of the compilation, and the dynamic linker, when the program is executed). I do not know whether your specific combination (a rather old g++ with a rather old Solaris) is supported (some googling shows me that some people can use it with an older gcc [3.4.3] with a newer Solaris [10]). If it is not supported, you can use the POSIX / Single Unix functions pthread_key_create(), pthread_setspecific() and pthread_getspecific(). They are somewhat slower, and not nearly as convenient, as the __thread qualifier, but at least they work.
You could implement this in a portable way using thread_specific_ptr from Boost.Thread.
If nothing else, you should be able to work out how to do this on Solaris using that as a reference.