目录
以下内容摘录自《ARM® Cortex™-A Series Version: 4.0 Programmer’s Guide.pdf》
Issues of Porting C code targeted at ARM Cortex-A series
Endianness
There are two basic ways of viewing bytes in memory – little-endian and big-endian. On big-endian machines, the most significant byte of an object in memory is stored at the least significant (closest to zero) address. On little-endian machines, the most significant byte is stored at the highest address.
ARM cores support both modes, but are most commonly used in, and typically default to little-endian mode.
Systems are built from multiple blocks and can include one or more cores, DSPs, peripherals, memory, and network connections. Whenever data is shared between these elements, there is a potential endianness conflict. If code is being ported from a system with one endianness to a system with different endianness, it might be necessary to modify that code, either to make it endian-neutral or to work with the opposite byte-ordering.
Cortex-A series processors provide support for systems of either endian configuration, controlled by the CPSR E bit that enables software to switch dynamically between viewing data as little or big-endian. Instructions in memory are always treated as little-endian.
Alignment
The alignment of accesses is significant on ARM cores. For the Cortex-A series of processors, unaligned accesses are supported, although you must enable this by setting the U bit in the CP15:SCTL register, indicating that unaligned accesses are permitted. This means that instructions to read or write words or halfwords can access addresses that are not aligned to word or halfword boundaries. However, load and store multiple instructions (LDM
and STM
) and load and store double-word (LDRD
or STRD
) must be aligned to at least a word boundary. Loads and stores of floating-point values must always be aligned. Additional alignment constraints might be imposed by the ABI that are stronger than those imposed by the ARM architecture.
These unaligned accesses can take additional cycles in comparison with aligned accesses and therefore alignment is also a performance issue. In addition, such accesses are not guaranteed to be atomic. This means that a external agent (another core in the system) might perform a memory access that appears to occur part way through the unaligned access.
unsigned char and signed char
Simple chars are not specifically defined and it is compiler dependent whether they are signed or unsigned. It made sense at the time for the compiler to treat simple chars as unsigned, whereas on the x86 simple chars are, by default, treated as signed. One workaround for users of GCC is to use the -fsigned-char
command line switch or --signed-chars
for RVCT, that forces all chars to become signed, but a better practice is to write portable code by declaring char variables appropriately.
Compiler packing of structures
Compilers are not permitted to re-order members of a structure and have to follow the alignment restrictions of the core architecture. This means that compilers might have to add unused bytes into user defined structures, for best performance and code size. Such padding is architecture specific and can therefore lead to portability problems if assumptions have been made about the location and size of this padding.
Marking a structure as __packed
in the ARM Compiler or using the attribute __packed__
in GCC, will remove any padding. This reduces the size of the structure and can be useful when porting code or for structures being passed from external hardware, but can reduce performance and increase code size, although generally it will be relatively efficient on Cortex-A series processors.
Function prototype
A function prototype is a declaration that omits the function body but gives the function name, argument and return types. It effectively gives a way to specify the interface of a function separately from its definition. Incorrectly prototyped functions can behave differently between different compilers.
Enumeration
Compilers can allocate different numbers of bytes to enum. Care is therefore required when enumerations are used; cross-linking of code and libraries between different compilers might not be possible if enums are used.