The difference between cross-compiler arm-linux-gnueabi and arm-linux-gnueabihf

I have never figured out what the problem is with these two cross-compilers before, so I googled it and summarized it as follows. I hope it can help brothers who are as confused as me…

1) What are ABI and EABI

ABI: Application Binary Interface (ABI) for the ARM Architecture
In computers, an application binary interface describes the low-level interface between an application (or other type) and the operating system or other applications.
ABI covers various details such as:

  • Size, layout, and alignment of data types.
  • Calling convention (controls how parameters of a function are passed and how return values are accepted), for example, whether all parameters are passed on the stack or some parameters are passed in registers; which register is used for which function parameter; the first one passed on the stack Whether function parameters are pushed to the stack first or last.
  • The encoding of system calls and how an application makes system calls to the operating system; and in a complete operating system ABI, the binary format of the target file, program library, etc.
  • A complete ABI, like the Intel Binary Compatibility Standard (iBCS), allows programs on an operating system that supports it to run unmodified on other operating systems that support this ABI.

ABI is different from application programming interface (API). API defines the interface between source code and library, so the same code can be compiled in any system that supports this API. ABI allows compiled target code to be used on ABI-compatible systems. It can run without modification.

2) EABI: Embedded ABI

ABI: Embedded Application Binary Interface (ABI) for the ARM Architecture
The Embedded Application Binary Interface specifies standard conventions for file formats, data types, register usage, stack organization optimization, and parameters in an embedded software.
Developers using their own assembly language can also use EABI as an interface to assembly language generated by a compatible compiler.
EABI-enabled compilers create object files that are compatible with code produced using a similar compiler, allowing developers to link against a library produced by a different compiler.
The main differences between EABI and the ABI for general-purpose computers are that privileged instructions are allowed in application code, dynamic linking is not required (sometimes prohibited), and a more compact stack frame organization is used to save memory. EABI is widely used by Power PC and ARM.

3) Two cross-compilers related to gnueabi: gnueabi and gnueabihf

The definitions of these two cross-compilers in the debian source are as follows:
gcc-arm-linux-gnueabi – The GNU C compiler for armel architecture
gcc-arm-linux-gnueabihf – The GNU C compiler for armhf architecture
It can be seen that these two cross-compilers are suitable for two different architectures, armel and armhf. The two architectures, armel and armhf, adopt different strategies for floating-point operations (only arm with FPU can support these two floating-point operations strategies)

In fact, these two cross-compilers are just different in the default value of the gcc option-mfloat-abi. The gcc option-mfloat-abi has three values: soft, softfp, and hard (the latter two require fpu floating point in the arm) Arithmetic unit, soft is compatible with the latter two, but softfp and hard modes are incompatible with each other):

  • soft: Does not use fpu for floating point calculations, even if there is an fpu floating point unit, but uses software mode.
  • softfp: The default value adopted by armel architecture (the corresponding compiler is gcc-arm-linux-gnueabi). It is calculated using fpu, but the parameters are passed in ordinary registers. In this way, when interrupting, only ordinary registers need to be saved, and the interrupt load is small. But the parameters need to be converted to floating point and then calculated.
  • hard: The default value adopted by armhf architecture (corresponding compiler gcc-arm-linux-gnueabihf), calculated using fpu, and passing parameters also using floating-point registers in fpu, eliminating the need for conversion, with the best performance, but interrupt load high.

4) Save the content of the c file used in the following test as mfloat.c

#include <stdio.h>
int main(void)
{
double a,b,c;
a = 23.543;
b = 323.234;
c = b/a;
printf(“the 13/2 = %f\
”, c);
printf(“hello world!\
”);
return 0;
}
  1. Compile with arm-linux-gnueabihf-gcc, use the “-v” option for more detailed information: arm-linux-gnueabihf-gcc -v mfloat.c

    COLLECT_GCC_OPTIONS=’-v’ -march=armv7-a’ -mfloat-abi=hard’ -mfpu=vfpv3-d16′ -mthumb’
    -mfloat-abi=hard, it can be seen that the hard hardware floating point mode is used.

  2. Compile using arm-linux-gnueabi-gcc: arm-linux-gnueabi-gcc -v mfloat.c

    COLLECT_GCC_OPTIONS=’-v’ -march=armv7-a’ -mfloat-abi=softfp’ -mfpu=vfpv3-d16′ -mthumb’
    -mfloat-abi=softfp, it can be seen that softfp mode is used.

5) Extended reading

The following describes the differences between soft-float and hard-float compilation and link implementation of ARM code. From the introduction of VFP floating point unit to the concepts of soft-float and hard-float

VFP (vector floating-point)
Starting from ARMv5, there are optional Vector Floating Point (VFP) modules. Of course, the latest ones such as Cortex-A8, Cortex-A9 and Cortex-A5 can be configured in a mode without VFP for chip manufacturers to choose.
After several years of development, VFP has VFPv2 (some ARM9 / ARM11), VFPv3-D16 (only uses 16 floating point registers, the default is 32) and VFPv3 + NEON (such as most Cortex-A8 chips). For ARM chips containing NEON, NEON generally shares registers with VFP.

Hard-float
The compiler directly compiles the code and sends it to the hardware floating point coprocessor (Floating Point Unit FPU) for execution. FPU usually has an additional set of registers to complete floating point parameter passing and operations.
Using an actual hardware floating-point unit, the FPU, will of course bring performance improvements. Because often a floating-point function call requires several or dozens of clock cycles.

Soft-float
The compiler converts floating-point operations into floating-point operation function calls and library function calls. There are no FPU instruction calls and no floating-point register parameter passing. The transfer of floating point parameters is also completed through ARM registers or stacks.
Current Linux systems use hard-float as the default compilation option, even if the system does not have any floating-point processor unit, which will generate illegal instructions and exceptions. Therefore, general system images use soft floating point to be compatible with processors without VFP.

armel ABI and armhf ABI
In armel, there are three conventions for floating point calculations. Taking gcc as an example, there are three corresponding -mfloat-abi parameter values: soft, softfp, hard.

  • Soft means that all floating-point operations are implemented at the software layer. The efficiency is certainly not high. There will be unnecessary conversions from floating point to integer and integer to floating point. It is only suitable for early ARM processors without floating point computing units;
  • Softfp is the current default setting of armel, which transfers floating-point calculations to the FPU, but the transfer of function parameters uses general-purpose integer registers instead of FPU registers;
  • Hard uses FPU floating point registers to pass function parameters to FPU for processing.

It should be noted that in terms of compatibility, soft is compatible with the latter two, but softfp and hard are not compatible. By default, armel uses softfp, so armel in hard mode is used as a separate abi, called armhf.
Using hard mode can save an average of 20 CPU cycles for each floating-point related function call. For an architecture like ARM where every cycle is important, such an improvement is undoubtedly huge.
Without changing the source code and configuration at all, using armhf can improve performance by 20% to 25% in some applications. For some programs that rely heavily on floating point operations, the performance can be improved by 300%.

Soft-float and hard-float compilation options:
In the CodeSourcery gcc compilation parameters, use -mfloat-abi=name to specify the floating point operation processing method. -mfpu=name to specify the type of floating point coprocessing.
Optional types such as fpa, fpe2, fpe3, maverick, vfp, vfpv3, vfpv3-fp16, vfpv3-d16, vfpv3-d16-fp16, vfpv3xd, vfpv3xd-fp16, neon, neon-fp16, vfpv4, vfpv4-d16, fpv4- sp-d16, neon-vfpv4, etc.
Use -mfloat-abi=hard (equivalent to -mhard-float) -mfpu=vfp to choose to compile to hard floating point. Use -mfloat-abi=softfp to be compatible with hardware with VFP and software implementation of soft-float. The runtime connector ld.so will select the computing unit when performing floating-point operations, whether it is a direct hardware call or a library. Function call, whether to execute libm under /lib or /lib/vfp. -mfloat-abi=soft (equivalent to -msoft-float) directly calls the soft floating point implementation library.

Under the ARM RVCT tool chain, define the fpu mode:
–fpu softvfp
–fpu softvfp + vfpv2
–fpu softvfp + vfpv3
–fpu softvfp + vfpv_fp16
–fpu softvfp + vfpv_d16
–fpu softvfp + vfpv_d16_fp16

Define floating point arithmetic types:
–fpmode ieee_full: The precision of all single-precision floats and double-precision doubles must be consistent with the IEEE standard. The specific mode can be dynamically specified at runtime;
–fpmode ieee_fixed : Round to the nearest implemented IEEE standard without inexact exceptions;
–fpmode ieee_no_fenv : Round to the nearest implemented IEEE standard without exception;
–fpmode std: non-standard numbers are flushed to 0 and rounded to the nearest implemented IEEE standard without exception;
–fpmode fast: More aggressive optimization, possibly with a slight loss of accuracy.