Using /etc/ld.so.preload in a multi arch setup - linux

Is there some way to use ld.so.preload and cover both 32bit and 64bit binaries?
If I list both the 32bit and 64bit versions of the fault handler in ld.so.preload then the loader always complains that one of them fails to preload for whatever command I run. Not exactly earth shaking since the error is more a warning but I could certainly do without the printout.
Instead of specifying an absolute path I tried specifying simply "segv_handler.so" in the hopes that the loader would choose the lib in the arch appropriate path (a 32bit version is in /lib and a 64bit version is in /lib64).
Not likely apparently.
Is there a way to setup ld.so.preload to be architecturally aware? Or if not is there some way to turn off the error message?

This works:
put library under /path/lib for 32bit one, and put the 64bit one under /path/lib64
and they should have the same name
put the following line in /etc/ld.so.preload:
/path/$LIB/libname.so
$LIB will get the value "lib" (for 32bit) or "lib64" (for 64bit) automatically.

There's no reason to try to use ld.so.preload like this. By default ld is smart enough to know that if you're running a 64bit app to only lookup 64bit libs, and same with 32bit.
Case in point, if you have
/lib64/libawesome.so
/lib/libawesome.so
And you try
gcc -lawesome -o funtime funtime.c
It'll choose whatever the default that gcc wants to build, ld will skip libraries of incorrect bit size for that build.
gcc -m64 -lawesome -o funtime funtime.c will pick the 64bit one
gcc -m32 -lawesome -o funtime funetime.c will pick the 32bit one.
This presumes that /etc/ld.so.conf lists /lib and /lib64 by default..

Sadly, I think the answer might be "Don't do that."
From glibc, elf/rtld.c:
There usually is no ld.so.preload file, it should only be used for emergencies and testing. So the open call etc should usually fail. Using access() on a non-existing file is faster than using open(). So we do this first. If it succeeds we do almost twice the work but this does not matter, since it is not for production use.

You can provide 32 and 64 bit library using special expansion keys in the path name.
For instance you can use /lib/$PLATFORM/mylib.so and create /lib/i386/mylib.so and /lib/x86_64/mylib.so. Linked will choose the correct one for your executable.

Related

Use private C++ runtime library on linux

In Windows, the dynamic loader always looks for modules in the path of the loaded executable first, making it possible to have private libraries without affecting system libraries.
The dynamic loader on Linux only looks for libraries in a fixed path, in the sense that it is independent on the chosen binary. I needed GCC 5 for its overflow checked arithmetic functions, but since the C++ ABI changed between 4.9 and 5, some applications became unstable and recompiling them solved the issue. While waiting for my distro [kubuntu] to upgrade the default compiler, is it possible to have newly compiled application linking to the new runtime, while packaged application still links to the old library, either by static linkage, or something that mimics the Windows behavior?
One way of emulating it would be to create a wrapper script
#!/bin/bash
LD_LIBRARY_PATH=$(dirname $(which your_file)) your_file
And after the linking step copy the affected library but it is sort of a hack.
You can use rpath.
Let's say your "new ABI" shared libraries are in /usr/local/newapi-libs.
gcc -L/usr/local/newapi-libs
-Wl,-rpath,/usr/local/newapi-libs
program.cpp -o program -lsomething`
The -rpath option of the linker is the runtime counterpart to -L. When a program compiled this way is run, the linker will first look in /usr/local/newapi-libs before searching the system library paths.
More information here and here.
You can emulate the Windows behavior of looking in the executable's directory by specifying -Wl,-rpath,.
[edit] added missing -L parameter and dashes before rpath.

gcc 4.x not supporting x87 FPU math?

I've been trying to compile gcc 4.x from the sources using --with-fpmath=387 but I'm getting this error: "Invalid --with-fpmath=387". I looked in the configs and found that it doesn't support this option (even though docs still mention it as a possible option):
case ${with_fpmath} in
avx)
tm_file="${tm_file} i386/avxmath.h"
;;
sse)
tm_file="${tm_file} i386/ssemath.h"
;;
*)
echo "Invalid --with-fpmath=$with_fpmath" 1>&2
exit 1
Basically, I started this whole thing because I need to supply an executable for an old target platform (in fact, it's an old Celeron but without any SSE2 instructions that are apparently used by libstdc++ by DEFAULT). The executable crashes at the first instruction (movq XMM0,...) coming from copying routines in libstdc++ with an "Illegal instruction" message.
Is there any way to resolve this? I need to be on a fairly recent g++ to be able to port my existing code base.
I was wondering if it's possible to supply these headers/sources from an older build to enable support for regular x87 instructions, so that no SSE instructions are referenced?
UPDATE: Please note I'm talking about compiled libstdc++ having SSE2 instructions in the object code, so the question is not about gcc command line arguments. No matter what I'm supplying to gcc when compiling my code, it will link with libstdc++ that already has built-in SSE2 instructions.
The real answer is not to use ANY --with-fpmath switches when compiling GCC. I got confused by the configure script switch statement thinking that it only supports sse or avx, while, in fact, the default value (not mentioned in this switch is "387"). So make sure you don't use --with-fpmath when running configure. I recompiled GCC without it and it now works fine.
Thanks.
The argument to tell gcc to produce code for a specific target is -march=CPU where CPU is the particular cpu you want. For an old celeron, you probably want -march=pentium2 or -march=pentium3
To control the fp codegen separately, newer versions of gcc use -mfpmath= -- in your case, you want -mfpmath=387.
All of these and many others are covered in the gcc documentation
edit
In order to use those flags for building libraries (such as libstdc++) that you'll later link in to programs, you need to configure the build for the library to use the appropriate flags. libstdc++ gets built as part of the g++ build, so you'll need to do a custom build -- you can use configure CXXFLAGS=-mfpmath=387 to set extra flags to use while building things.
Please note the question was about compiled libstdc++ having SSE2 instructions in the object code, so the question was not about gcc command line arguments. No matter what I'm supplying to gcc when compiling my code, it will link with libstdc++ that already has built-in SSE2 instructions.
The real answer is not to use ANY --with-fpmath switches when compiling GCC. I got confused by the configure script switch statement thinking that it only supports sse or avx, while, in fact, the default value (not mentioned in this switch is "387"). So make sure you don't use --with-fpmath when running configure. I recompiled GCC without it and it now works fine.

using older version of a shared linux library while compiling C

I am trying to use libfann version 2.0.1 instead of the newest version 2.2.0, but could not figure out how to do so. Any thoughts on how to do that?
normally that works perfectly:
gcc fann_calculator.c -o run_fann_calculator -lfann -lm
where fann_calculator.c contains a program that calls a neural network.
Thanks
It depends upon where the two libraries sit. If they are installed in the same directory (e.g. both installed in /usr/lib/) you'll probably get the youngest one.
I suggest to carefully read the ld.so(8) and ldd(1) man pages. You certainly can trace what library is loaded (with e.g. the LD_DEBUG envirnonment variable). Don't forget to re-run ldconfig appropriately after library installation.
You could also play some LD_LIBRARY_PATH trick; for instance, set it to $HOME/lib:/usr/lib and install appropriate symlinks in your $HOME/lib/ to the precise library you want. For instance, you might do
ln -s /usr/lib/libfann.so.2.0.1 $HOME/lib/libfann.so.2
export LD_LIBRARY_PATH=$HOME/lib:/usr/lib:/lib
then check with ldd run_fann_calculator that you get the expected [version of the] libfann library.
Don't forget to read the Program Library Howto. You might want to pass appropriate flags to ld such as -rpath. You may need to pass them using gcc, perhaps with Gcc Link Options such as -Wl

How do shared libraries work in a mixed 64bit/32bit system?

Good morning,
on a 64bit RedHat box we have to compile and run a 32bit application. Meanwhile I managed to compile the gcc version needed (4.0.3) and all required runtime libraries in 32bit and have set the LD_LIBRARY_PATH to point to the 32bit versions, but now during the remaining build process, a small java program needs to be executed which is installed in /usr/bin as a 64bit program, which now finds the 32bit version of libgcc_s.so first.
In general, if I set the LD_LIBRARY_PATH to the 32bit versions, I break the 64bit programs and vice versa.
How it this supposed to work at all? I am certain I am not the first person with this problem at hand. How is it solved usually?
Regards,
Stefan
Add both the 32-bit and 64-bit directories to the LD_LIBRARY_PATH.
If you do this, then the ld.so for 32-bit or 64-bit will use the correct libraries.
e.g. A 32-bit test app "test32" and 64-bit test app "test", with a locally-installed copy of a (newer version of) gcc and binutils in a user homedir, to avoid clobbering the system-wide install of gcc:
=> export LD_LIBRARY_PATH=/home/user1/pub/gcc+binutils/lib:/home/user1/pub/gcc+binutils/lib64
=> ldd ./test32
libstdc++.so.6 => /home/user1/pub/gcc+binutils/lib/libstdc++.so.6 (0x00111000)
libgcc_s.so.1 => /home/user1/pub/gcc+binutils/lib/libgcc_s.so.1 (0x00221000)
=> ldd ./test
libstdc++.so.6 => /home/user1/pub/gcc+binutils/lib64/libstdc++.so.6 (0x00007ffff7cfc000)
libgcc_s.so.1 => /home/user1/pub/gcc+binutils/lib64/libgcc_s.so.1 (0x00007ffff7ad2000)
(Less interesting library paths removed)
This shows that the loaders know to ignore the libraries of the wrong architecture, at least on this Scientific Linux 6.3 (RHEL-derived) system. I would expect other distros to work similarly, but haven't tested this.
This may have only started being the case more recently than your (unspecified) distro version, however.
On Solaris one can use LD_LIBRARY32_PATH and LD_LIBRARY64_PATH, but that isn't supported on Linux.
In general, you should just never need to set LD_LIBRARY_PATH at all in the first place:
either install needed libraries into
/usr/lib32 or /usr/lib64 as
appropriate, or
build your 32-bit application with -Wl,-rpath=/path/to/32-bit/libs
As a workaround, wrap the Java call in a small shell script which unsets LD_LIBRARY_PATH and then calls the executable. Alternatively, this might also work:
LD_LIBRARY_PATH= java...
Note the space between "=" and the name of the executable.
Just set LD_LIBRARY_PATH to both paths (use colons to delimit). The linker will ignore the libraries that it cannot read.
I have faced this exact same problem when remastering a 32bit tinycore64 system running a 64bit kernel.
After much searching, I have discovered why these comments would make sense to both of them.
"That would be nice, but - at least in my environment - it did not
appear to work. The loader did complain; it did not simply skip the
libraries that do not match the bit-ness. Sadly!" - struppi
"This is very strange, could you describe how things failed? Also,
perhaps post the output of ldd?" - Adam Goode
And why this comment might appear to be true but is actually incorrect.
The linker will ignore the libraries that it cannot read.
This link shed's some light on it.
http://www.markusbe.com/2009/09/about-running-32-bit-programs-on-64-bit-ubuntu-and-shared-libraries/
And more to the point, you will find the ld.so manpage enlightening.
It turns out the path name can make a difference in what the runtime linker ld.so chooses as the library to load. On my 64bit linux system I have a range of odd directory names in addition to the standard ones. e.g. /lib/x86_64-linux-gnu. I actually thought I'd experiment by moving the libraries in that path to /lib64. When I did that, guess what happened? suddenly my 64bit app (brctl in this case) didn't work and complained with "Wrong ELF class". Hello... now we're onto something.
Now I'm not 100% certain but the key seems to be related to rpath token expansion.
I suspect the ${PLATFORM} expansion may have something to do with it. And the name x86_64 must be part of that.
In any case, I found when I put my 64-bit libraries in library paths named
x86_64-linux-gnu as apposed to just lib64, then they were preferred over the 32bit ones and things worked.
In your case, you probably want to do something very similar for 32bit libraries on 64. Try i386-linux-gnu.
So in my case where I am installing 64bit shared libraries onto a 32bit userland, I created the following paths:
mkdir /lib/x86_64-linux-gnu/
mkdir /usr/lib/x86_64-linux-gnu/
ln -s /lib/x86_64-linux-gnu /lib64
ln -s /usr/lib/x86_64-linux-gnu /usr/lib64
Add your 64bit libraries to the 64bit paths and 32bit libraries to the 32bit /lib & /usr/lib paths only.
Then add the 64bit specific paths to ld.so.conf and update your cache with ldconfig
Now your 32-bit & 64-bit applications will run seamlessly.

Can you compile 32-bit Apache DSOs (Oracle HTTP Server) on a 64-bit machine?

I've migrated an Oracle database and Oracle HTTP server install from a 32-bit machine to a 64-bit machine - both machines running Linux. Oracle Database is 64-bit, but the (Apache) HTTP server is 32-bit.
I use some non-Oracle DSOs (mod_ntlm for one) but whenever I run the standard "make install" type thing I end up with a 64-bit module.
Is there a standard way to compile 32-bit Apache modules on a 64-bit machine?
As an alternative to Andrew Medico's answer, use '-m32' for 32-bit compilations and '-m64' for 64-bit compilations on PPC or SPARC or Intel machines - since you don't actually mention which chip architecture you are using and that notation works on all of these.
I often use:
CC="gcc -m32" ./configure
to ensure a 32-bit compilation (or, more frequently, CC="gcc -m64" to ensure 64-bit compilation).
Question: "Is CC an environment variable used by make?"
Answer: Yes, though in this case, it is also recognized by configure, which is a shell script generated by autoconf. The notation I used - which is what I use at the command line - sets CC in the environment while the configure command is run. The other answer suggests using:
./configure CC="gcc -m32"
I assume that works and achieves much the same effect; I've not tried it so I don't know that it works.
If you run ./configure --help | less, you will see information (often just standard information) about how to use the script. And at the end, it will list (some of the) relevant environment variables, of which CC is one.
The advantage of setting the C compiler to "gcc -m32" is that the 32-bit flag is set every time the compiler is used - there is very little room for it to go wrong. If you set a flags variable (CFLAGS, etc), there is a chance that some command won't use it, and then things can go awry.
Also, going back to the question, make certainly uses a variable (macro) called CC. And you can set that on the make command line:
make CC="gcc -m32"
That overrides any setting in the makefile. By contrast, using an environment variable, the setting in the makefile overrides the value in the environment, so setting CC as an environment variable is less helpful. Although make -e gives the environment precedence over the makefile, it is usually a dangerous option to use - it can have unexpected side-effects.
./configure CFLAGS="-march=i686"
should do it
Along with the -m32 flag in gcc, you may need to include the -melf_i386 flag for ld to properly link the 32bit object files to the 32bit libraries if you have both the 32bit and 64bit libraries. The standard ld on 64bit linux boxes will default to the 64bit libraries and you get a compatibility error when the linking occurs.

Resources