How to see the compilation platform of a static library file - c

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

Related

On Windows MSVC, is it possible to merge some .obj into one .obj? If yes, how should I do that?

For example, there is three object files a.obj b.obj c.obj just compiled out with cl, and it is desired to combine them into one combined.obj.
A comment of an SO question points out that on *nix it's possible to do this kind of thing with ld. However, cl and link all seems only support .exe, .dll and .lib as output.
The whole procedure of what I want to do with the combined object file as follows:
a.obj b.obj c.obj -> combined.obj
combined.obj d.obj e.obj -> executable.exe
My problem is solved. a.obj b.obj c.obj use some variables and functions yet to be linked, and I thought that .lib can't tolerant missing functions since it is a library, but in fact it is OK. I can just merge them into an .lib file:
lib *.obj /OUT:combined.lib
You can apply the method employed here also to the COFF files created by cl.exe, provided that your build of ld supports the respective input and output formats and those formats lend themselves to the process.
What you can do in such a case is this (and yes $INPUTS means you can give multiple object files as you wanted):
ld --oformat pe-x86-64 -r $INPUTS -o $OUTPUT
The --oformat pe-x86-64 (aka AMD64, x64 on Windows) is necessary whenever the ld has been built with a different default output format.
If that's the case and you didn't give --oformat you will get something like:
ld: relocatable linking with relocations from format pe-x86-64 (input.obj) to format elf64-x86-64 (output.obj) is not supported
However the process doesn't work for all input/output format combinations, as I learned with ld 2.34 on Ubuntu 20.04:
ld: relocatable linking with relocations from format pe-i386 (input.obj) to format pe-i386 (output.obj) is not supported
NB: At this point I had no luck to get this to work with lld-link or ld.lld (both available through modern VS versions), though.
Seems not, but it is convenient to merge them into an .lib:
lib *.obj /OUT:combined.lib

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]

Wrong ELF class with both 32 and 64bits lib

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

why is binary compiled with gcc not stripped by default

When I compile my program gcc -o myprog myprog.c, the produced binary is not stripped:
myprog: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically
linked (uses shared libs), for GNU/Linux 2.6.26,
BuildID[sha1]=0x2697ed96b65e8a11239af0a44abc7896954b6e20, not stripped
I am wondering why gcc produces non-stripped binaries by default, when I did not provide any debuging parameter.
Should all binaries be stripped after being compiled, i.e. using strip myprog? Or is there an advantage of having a binary non-stripped?
AFAICS, most binaries in /bin/, /usr/bin/ are stripped.
AFAIK Once the binary is stripped you wont be able to get the stripped information back until or unless you regenerate the binary. stripping is useful when you have memory constraints to look after. This might be the reason strip is not enabled by default in GCC.

file format not recognized; treating as linker script

i'm new on gcc compiler.
My friend wrote this script (graphic filter) for me but i can't use it because i receive some error.
I have 2 directory and a C file:
-dir- include --> basics.h common.h freeimage.h hqx.h imageIO.h pcxIO.h
-dir- lib --> libfreeimage-3.13.1.so libfreeimage.a libfreeimage.so.3 libhqx.a libhqx.so libhqx.so.1 libhqx.so.1.0.0
scaling.c
i try to compile with this command:
gcc scaling.c -I./include -L./lib -lm -lfreeimage -lhqx -lstdc++ -o filter
But i receive this error:
/usr/lib/gcc/i486-slackware-linux/4.2.4/../../../../i486-slackware-linux/bin/ld:./lib/libhqx.so: file format not recognized; treating as linker script
/usr/lib/gcc/i486-slackware-linux/4.2.4/../../../../i486-slackware-linux/bin/ld:./lib/libhqx.so:1: syntax error
collect2: ld returned 1 exit status
Thanks in advance and sorry for my english.
The linker will treat any file that doesn't look like an object file or library as a linker script containing commands to specify how linking should be done. Things like load addresses, section definitions, etc.
Apparently libhqx.so doesn't look like a shared library on you system. I assume it was built on your friend's system?
To get a clue about what the file is, use the file command. You should get something like:
main% file /lib/libc-2.11.2.so
/lib/libc-2.11.2.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (GNU/Linux), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
If not, you'll have to build or find a library compatible with your system.
I had a similar problem yesterday, and I think your libhqx.so was a symbolic link to libhqx.so.1.0.0 or to libhqx.so.1 in your friend's machine, and when you copied this files, this link had broken. (at least that was the situation in our system, and the problem solved after we remove the .so file, and create the right symbolic link)

Resources