1. Overview
We can install both 32-bit and 64-bit libraries on a 64-bit Linux system to run our applications. Here, we’re talking about C/C++ libraries, compiled for specific architectures.
We may sometimes wish to know if a given library is 32-bit or 64-bit. In this short tutorial, we’ll learn a few ways to determine the format of a library.
2. Shared Libraries and Static Libraries
A library groups a collection of pre-compiled code into a single file so it can be used in different programs.
In Linux, we have two types of libraries:
- Static — bound to a program statically at compile-time, typically named as “*.a“
- Shared — loaded when a program launches and loaded into memory at runtime, typically named as “*.so“
A static library isn’t an executable. Instead, it’s a file in the ar format. It’s simply an archive of other files, such as ELF object files.
On the other hand, a shared library is an ELF file.
The ELF header defines whether the library uses 32-bit or 64-bit addresses.
In this tutorial, we’ll use the file and objdump commands to determine the format of a library. We’ll look at how this applies to both static and shared libraries.
3. Using the file Command
The file command is a convenient utility to check file types. We can use file to tell us the format of a library.
3.1. Shared Libraries
First, let’s test it on two shared libraries:
$ file /usr/lib/libc-2.33.so
/usr/lib/libc-2.33.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, ....
$ file /usr/lib32/libc-2.33.so
/usr/lib32/libc-2.33.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (GNU/Linux), dynamically linked, ...
Here, we’ve executed file on 32-bit and a 64-bit library files. As we can see, the file command reads the ELF header and reports each library’s detailed information, including the address width it uses.
3.2. Static Libraries
Next, let’s do similar tests on static libraries:
$ file /usr/lib/libc.a
/usr/lib/libc.a: current ar archive
$ file /usr/lib32/libc.a
/usr/lib32/libc.a: current ar archive
This time, the file command just tells us they are ar archives but doesn’t report if they are 32-bit or 64-bit.
This is because a static library is merely an archive instead of an ELF file. The file command does not look at all ELF object files in a static library and reads their headers.
4. Using the objdump Command
The objdump command is a member of the package GNU Binutils. It displays information from object files.
We can use the -f option to read the header of an ELF file.
4.1. Shared Libraries
First, let’s see what objdump outputs if we execute it on some shared libraries:
$ objdump -f /usr/lib/libc-2.33.so
/usr/lib/libc-2.33.so: file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x0000000000027c60
$ objdump -f /usr/lib32/libc-2.33.so
/usr/lib32/libc-2.33.so: file format elf32-i386
architecture: i386, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x0001ebc0
In the output above, the “file format” field reports the ELF file uses 64-bit (elf64-…) or 32-bit (elf32-…) addresses.
Therefore, the “*/usr/lib/libc-2.33.so” file is a 64-bit library and the other one is a 32-bit library. Also, if we have a look at their “start address*” fields, they have 64-bit and 32-bit wide addresses respectively.
4.2. Static Libraries
Next, let’s run the same command on a static library:
$ objdump -f /usr/lib/libc.a
In archive /usr/lib/libc.a:
init-first.o: file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x0000000000000000
libc-start.o: file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x0000000000000000
sysdep.o: file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000000:
start address 0x0000000000000000
...
The output above shows the objdump command working through all object files in the static library outputting their ELF headers.
This solution works but can produce a large output. For example, the output above runs to over 10,000 lines.
4.3. Getting a Straightforward Output
To summarize the ELF header information, we can pipe the output of objdump to awk to extract the file format value by search and replace, and remove duplicates:
$ objdump -f /usr/lib/libc.a | awk 'sub(/.*file format /,"") && !a[$0]++'
elf64-x86-64
Now, the output means all object files in the static library are using 64-bit addresses. So, we can say /usr/lib/libc.a is a 64-bit static library.
Finally, let’s test the command on a 32-bit static library:
$ objdump -f /usr/lib32/libc.a | awk 'sub(/.*file format /,"") && !a[$0]++'
elf32-i386
The “elf32-*” indicates all object files in the library use 32-bit addresses. Thus, it’s a 32-bit library.
5. Conclusion
In this article, we learned how to check if a library is 32-bit or 64-bit in Linux.
If it’s a shared library, the file command is probably the most straightforward solution.
However, if it’s a static library, then we need to read the headers of object files in the library, for which we can use objdump.