ARMv8 AArch64 and AArch32 Compatibility Constraints
The ARMv8 architecture introduces a significant shift in the way 32-bit and 64-bit applications and libraries interact. ARMv8 supports two execution states: AArch64, which is the 64-bit execution state, and AArch32, which is the 32-bit execution state. While ARMv8 processors are designed to be backward compatible with ARMv7 (32-bit) instructions, this compatibility does not extend to mixing 32-bit libraries with 64-bit applications. The ARMv8 architecture allows a processor to operate in either AArch64 or AArch32 mode, but not both simultaneously. This means that a 64-bit application running in AArch64 mode cannot directly call functions or link against libraries compiled for AArch32.
The confusion often arises from the term "backward compatibility," which is sometimes misinterpreted as the ability to mix 32-bit and 64-bit code within the same application. However, backward compatibility in ARMv8 refers to the ability of the processor to run legacy 32-bit applications in AArch32 mode, not to the interoperability of 32-bit libraries with 64-bit applications. When a 64-bit application is running, the entire execution environment, including all linked libraries, must also be 64-bit. Similarly, if a 32-bit application is running, all libraries must be 32-bit.
This architectural constraint is rooted in the differences between the AArch64 and AArch32 instruction sets, register sets, and memory models. For example, AArch64 has 31 general-purpose 64-bit registers, while AArch32 has 16 general-purpose 32-bit registers. Additionally, the calling conventions, stack alignment, and exception handling mechanisms differ between the two execution states. These differences make it impossible for the processor to seamlessly switch between AArch64 and AArch32 modes within the same application.
Compiler and Linker Limitations in Mixed 32-bit/64-bit Environments
The issue of using a 32-bit library in a 64-bit ARMv8 application is further complicated by the limitations of the compiler and linker. In the case described, the user attempted to compile the OpenSSL 1.0.1p library, which only supports ARMv7 (32-bit), using the aarch64-linux-gnu-gcc
compiler. The -march=armv7-a
flag was used in an attempt to generate 32-bit code, but this flag is not supported by the aarch64-linux-gnu-gcc
compiler. This is because the aarch64-linux-gnu-gcc
compiler is specifically designed to generate code for the AArch64 execution state and does not support generating code for the AArch32 execution state.
When the user switched to the armv8l-linux-gnueabihf-gcc
compiler, which is a 32-bit compiler, the OpenSSL library compiled successfully. However, linking the 32-bit OpenSSL library with a 64-bit application resulted in a linker error indicating an "incompatible library." This error occurs because the linker cannot resolve symbols between the 64-bit application and the 32-bit library. The linker expects all object files and libraries to be in the same instruction set architecture (ISA). Mixing ISAs within the same application is not supported by the ARMv8 architecture or the toolchain.
The ARMv8 toolchain does not provide a mechanism to bridge the gap between AArch64 and AArch32 code. While some architectures, such as x86-64, allow for mixed 32-bit and 64-bit code through the use of compatibility layers or thunks, ARMv8 does not provide such a mechanism. This is due to the fundamental differences in the instruction sets and execution states, as well as the performance and complexity overhead that such a mechanism would introduce.
Resolving Incompatibility by Upgrading to AArch64-Compatible Libraries
The most effective solution to the problem of using a 32-bit library in a 64-bit ARMv8 application is to upgrade to a version of the library that supports AArch64. In the case of OpenSSL, the user should consider upgrading to OpenSSL 1.1.1 or later, which provides full support for the AArch64 execution state. This approach eliminates the need to mix 32-bit and 64-bit code and ensures that the entire application, including all libraries, runs in the AArch64 execution state.
Upgrading to an AArch64-compatible library involves several steps. First, the user must obtain the source code for the newer version of the library. In the case of OpenSSL, this can be done by downloading the source code from the official OpenSSL website or through a package manager. Next, the user must configure the library to target the AArch64 architecture. This can be done by specifying the appropriate compiler and flags during the configuration step. For example, the following command can be used to configure OpenSSL for AArch64:
./Configure linux-aarch64 --cross-compile-prefix=aarch64-linux-gnu- --prefix=/path/to/install
After configuring the library, the user can compile and install it using the standard make
and make install
commands. Once the library is installed, the user can link it with their 64-bit application without encountering any compatibility issues.
If upgrading to an AArch64-compatible library is not feasible, an alternative approach is to run the 32-bit library in a separate 32-bit process and communicate with it using inter-process communication (IPC) mechanisms such as sockets, shared memory, or message queues. This approach allows the 64-bit application to leverage the functionality of the 32-bit library without directly linking to it. However, this approach introduces additional complexity and performance overhead, as data must be serialized and deserialized for communication between the 32-bit and 64-bit processes.
In conclusion, the incompatibility between 32-bit libraries and 64-bit applications on ARMv8 is a fundamental limitation of the architecture and toolchain. The most effective solution is to upgrade to a version of the library that supports AArch64. If this is not possible, alternative approaches such as IPC can be used, but they come with their own set of challenges. By understanding the architectural constraints and toolchain limitations, developers can make informed decisions and avoid common pitfalls when working with ARMv8 processors.