Wrong ELF class with both 32 and 64bits lib - c

I am trying to solve a challenge by using LD_PRELOAD to load my own strcmp library.
I first tried to compile my library with gcc -shared -fPIC strcmp.c -o strcmp.so, but when I tried to execute my file with LD_PRELOAD=/path/to/lib/strcmp.so ltrace ./exec, I had a the error :
object '/path/strcmp.so' from LD_PRELOAD cannot be preloaded (wrong ELF class: ELFCLASS64): ignored
By comparing file /path/to/strcmp.so and file exec, I found out that my exec file was a ELF 32-bit LSB executable and that my lib was a ELF 64-bit LSB shared object.
Then I tried to compile my lib with gcc -m32 -shared -fPIC strcmp.c -o strcmp.so, but when executing I have the same error (but this time with ELFCLASS32) :
object '/path/strcmp.so' from LD_PRELOAD cannot be preloaded (wrong ELF class: ELFCLASS32): ignored
Any suggestions? How can I have the same error with both 32 and 64 bits version of my lib?

As you noticed, if you have a single 32-bit shared library, you will get that warning when 64-bit programs are run. If you have a single 64-bit library, you get that warning when you run 32-binaries. We need your system to have both 32- and 64-bit versions of your libraries, and to allow the system to choose which one to use as needed. You can accomplish that with the following changes:
Compile both a 32-bit and 64-bit version of your library, and put them in /usr/lib and /usr/lib64 respectively on RedHat-based systems. Debian uses a different library naming scheme which unfortunately is not very consistent, so I'll leave it an exercise for the reader to determine the right place to put the two libraries on Debian systems.
Change your preload to remove all paths, like so: export LD_PRELOAD=strcmp.so This will allow the system to search only the correct library directory when it looks for a 32-bit or 64-bit library.
If you want to patch only one architecture, say 32-bit, then compile a 32-bit version of your library, and then compile an empty file into a 64-bit shared library of the same name. Place them both as described above.
Note that this only works if you use the system library directories. Even /usr/local/lib and /usr/local/lib64 are not allowed.

You should run 32-bit dynamic linker directly:
ltrace /lib/ld-linux.so.2 --preload /path/to/lib/strcmp.so ./exec

Related

Create non-PIC shared libraries with ld

I have a bunch of object files that have been compiled without the -fPIC option. So the calls to the functions do not use #PLT. (source code is C and is compiled with clang).
I want to link these object files into a shared library that I can load at runtime using dlopen. I need to do this because I have to do a lot of setup before the actual .so is loaded.
But every time I try to link with the -shared option, I get the error -
relocation R_X86_64_PC32 against symbol splay_tree_lookup can not be used when making a shared object; recompile with -fPIC
I have no issues recompiling from source. But I don't want to use -fPIC. This is part of a research project where we are working on a custom compiler. PIC wouldn't work for the type of guarantees we are trying to provide in the compiler.
Is there some flag I can use with ld so that it generate load time relocating libraries. In fact I am okay with no relocations. I can provide a base address for the library and dlopen can fail if the virtual address is not available.
The command I am using for compiling my c files are equivalent to -
clang -m64 -c foo.c
and for linking I am using
clang -m64 -shared *.o -o foo.so
I say equivalent because it is a custom compiler (forked off clang) and has some extra steps. But it is equivalent.
It is not possible to dynamically load your existing non PIC objects with the expectation of it working without problems.
If you cannot recompile the original code to create a proper shared library that supports PIC, then I suggest you create a service executable that links to a static library composed of those objects. The service executable can then provide IPC/RPC/REST API/shared memory/whatever to allow your object code to be used by your program.
Then, you can author a shared library which is compiled with PIC that provides wrapper APIs that launches and communicates with the service executable to perform the actual work.
On further thought, this wrapper API library may as well be static. The dynamic aspect of it is performed by launching the service executable.
Recompiling the library's object files with the -fpic -shared options would be the best option, if this is possible!
man ld says:
-i Perform an incremental link (same as option -r).
-r
--relocatable
Generate relocatable output---i.e., generate an output file that can in turn serve as input to ld. This is often called partial linking. As a side effect, in environments that support standard Unix magic numbers, this option also sets the output file’s magic number to "OMAGIC". If this option is not specified, an absolute file is produced. When linking C++ programs, this option will not resolve references to constructors; to do that, use -Ur.
When an input file does not have the same format as the output file, partial linking is only supported if that input file does not contain any relocations. Different output formats can have further restrictions; for example some "a.out"-based formats do not support partial linking with input files in other formats at all.
I believe you can partially link your library object files into a relocatable (PIC) library, then link that library with your source code object file to make a shared library.
ld -r -o libfoo.so *.o
cp libfoo.so /foodir/libfoo.so
cd foodir
clang -m32 -fpic -c foo.c
clang -m32 -fpic -shared *.o -o foo.so
Regarding library base address:
(Again from man ld)
--section-start=sectionname=org
Locate a section in the output file at the absolute address given by org. You may use this option as many times as necessary to locate multiple sections in the command line. org must be a single hexadecimal integer; for compatibility with other linkers, you may omit the leading 0x usually associated with hexadecimal values. Note: there should be no white space between sectionname, the equals sign ("="), and org.
You could perhaps move your library's .text section?
--image-base value
Use value as the base address of your program or dll. This is the lowest memory location that will be used when your program or dll is loaded. To reduce the need to relocate and improve performance of your dlls, each should have a unique base address and not overlap any other dlls. The default is 0x400000 for executables, and 0x10000000 for dlls. [This option is specific to the i386 PE targeted port of the linker]

C: trouble statically linking binary that uses openssl AES-256 encryption

I'm trying to produce a static binary that can be run on generic linux machine (same machine architecture, same bitnes, same endienness and compatible kernel system call interface). When I pass -static to gcc I get the following warning:
# gcc -static testme.c -lssl -lcrypto -ldl -lltdl -static-libgcc
/usr/lib/gcc/i486-slackware-linux/4.8.2/../../../libcrypto.a(dso_dlfcn.o): In function `dlfcn_globallookup':
dso_dlfcn.c:(.text+0x21): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
#
Although the binary runs some systems I've tried it on I suppose the warning means my static binary will not run on a system with different glibc version.
I included -ldl and -lltdl along the other libs to be linked, in an attempt to eliminate the warning, but still get the same. What am I doing wrong ? and how can I get rid of the warning ?
The actual code can be seen on the obash testing branch on github.
once you produce obash it should then be used to produce a reusable static binary by calling it with "-r" flag.
Since it's openssl that pulls dlopen into the equation is there an alternative way of doing acceptably safe symmetric encrypting that will not use dlopen and be safe to use even when statically linked ?

Gcc on OS X: Undefined symbols for architecture x86_64

I am writing an application that has multiple subdirectories. I have created a Makefile structure such that the subdirectories compile the file and do "ar rvs" and "ranlib libxxx.a" to create archives into the parent directory for linking.
However the "ld" command is running into the following problem.
ld: warning: ignoring file ./libxxx.a, file was built for archive which is not
the architecture being linked (x86_64):
./libxxx.a Undefined symbols for architecture x86_64:
I am using gcc on Mac OS X 10.10.1
I read many posts on this. I tried "gcc -arch i386", then I encounter the same error for i386
Undefined symbols for architecture i386:
I installed gcc-4.9.2 and tried using it instead of the default gcc, with no luck. I tried using x86_64-apple-darwin14.0.0-g++-4.9.2 and that did not help either.
The errors you are seeing mean that you have a mixture of i386 and x86_64 code in the build, and you need to be consistent. Unless there's a compelling reason to do otherwise (I'd be curious to know what it is), you should be compiling everything for 64-bit only. Using gcc on Mac, that is normally the default, but you can force it by adding a -m64 flag to the compilations. One way of doing that is to set CC="gcc -m64" on the make command line; there are other better ways too, but the details depend on your makefile contents.
To resolve: first, remove all the libraries and object code you've built in your project area (maybe make clean will do it — if you wrote a clean target). Then, fettle the value of CC or its flags (CFLAGS ultimately, but how CFLAGS is built depends on the makefile) so that 64-bit compilation is enforced. Then make sure you're using that in all compilations. If you don't see the -m64, you've got a problem.
If you must use 32-bit, substitute -m32 for -m64.
The discussion above assumes you are using gcc to run the ld command. If you are not, then you're on your own until you use gcc to run the ld command. In my view, you've got better things to do with your life than work out how to run the ld command correctly; I certainly have.

How to see the compilation platform of a static library file

I had a static library file. How can I see whether it is compiled in i386 or in arm platform. Thanks.
objdump is your friend ;)
$ objdump -f lib/lib.a
In Unix (and similar - say, Linux or Minix) systems, you can use the "file" utility:
%file /lib/libc.so.7
libc.so.7: ELF 64-bit LSB shared object, x86-64, version 1 (FreeBSD), dynamically linked, stripped
(the % indicates a shell prompt and is not part of the command)
As for Windows, I don't know if there is a built-in command already present, but if not, you can find the utility on this page: http://gnuwin32.sourceforge.net/packages.html (the file package is about 1/3 down the page).
EDIT: For static libraries (.a files), you first need to extract them and check a .o file:
%cp /usr/lib/libchipmunk.a .
%ar -x libchipmunk.a
%file *.o
chipmunk.c.o: ELF 64-bit LSB relocatable, x86-64, version 1 (FreeBSD), not stripped
<snip>
WARNING: ar -x ... will pollute the local directory, so be sure to copy the files somewhere else (say /tmp/something) first!
I'm sure there is a way to directly check into these files, but this works just as well!
Use file or objdump. file always works but objdump will give you more detailed information about libraries and archives and executables.
file gives you general information about the platform on linux.
e.g.
file /usr/lib/libfoo.a
or for a executable binary
file `which foo`
For libraries linked to iOS apps, here's how to see the architectures of a .a file:
file /path/to/library.a
Example output for a lib built for armv7, armv7s (iPhone 5), arm64, x86_64, and i386:
/path/to/library.a: Mach-O universal binary with 5 architectures: [i386:Mach-O object i386] [x86_64:Mach-O 64-bit object x86_64] [arm_v7:Mach-O object arm_v7] [arm_v7s:Mach-O object arm_v7s] [arm64]
/path/to/library.a (for architecture i386): Mach-O object i386
/path/to/library.a (for architecture x86_64): Mach-O 64-bit object x86_64
/path/to/library.a (for architecture armv7): Mach-O object arm_v7
/path/to/library.a (for architecture armv7s): Mach-O object arm_v7s
/path/to/library.a (for architecture arm64): Mach-O 64-bit object arm64

Shared library not found

I am running Ubuntu 10.10 and a C program that uses a shared library libcrypto.so
When compiling it, though I have a Makefile that has the option -lcrypto, I get this message:
/usr/bin/ld: skipping incompatible ./libcrypto.so when searching for -lcrypto
/usr/bin/ld: cannot find -lcrypto
I did export the current directory before by doing:
export LD_LIBRARY_PATH=D_LIBRARY_PATH:.
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
So what is wrong with my library and what can I do?
The first error message probably indicates that you have a 64-bit library but are doing a 32-bit compilation, or a 32-bit library but are doing a 64-bit compilation.
Run file libcrypto.so to see what type it is, then adjust your build (restart - remove all the object files) with either the option '-m32' or '-m64' to get the write build mode. If you can't work out how else to get that into the makefile, use:
make CC="gcc -m32" CXX="g++ -m32"
(or the 64-bit version if that's what you're after).
Could you post the output of this:
$ file ./libcrypto.so
And check that it is the right version for your machine? (I.e. 32 vs 64 bit, etc?)

Resources