1.2.1. Unaligned pointers

The C and C++ standards specify that a pointer to a type cannot be less aligned than the natural alignment of the type. This improves code size and performance. Therefore, by default, the ARM compiler expects normal C and C++ pointers to point to an aligned word in memory. A type qualifier __packed is provided to enable unaligned pointer access (see the section describing variable declaration keywords in the compiler reference in RealView Compilation Tools v3.0 Compiler and Libraries Guide).

For example, if the pointer int * is used to read a word, the ARM compiler uses an LDR instruction in the generated code. This works as expected when the address is a multiple of four (that is, on a word boundary). However, if the address is not a multiple of four, then an LDR instruction returns a rotated result rather than performing a true unaligned word load. The rotated result depends on the offset and endianness of the system.

If your code loads data from a pointer that points to the address 0x8006, for example, you might expect to load the contents of bytes from 0x8006, 0x8007, 0x8008, and 0x8009. However, on an ARM processor, this access loads the rotated contents of bytes from 0x8004, 0x8005, 0x8006, and 0x8007.

Therefore, if you want to define a pointer to a word that can be at any address (that is, that can be at a non-natural alignment), you must specify this using the __packed qualifier when defining the pointer:


__packed int *pi; // pointer to unaligned int

The ARM compiler does not then use an LDR, but generates code that correctly accesses the value regardless of the alignment of the pointer. This generated code is a sequence of byte accesses or, depending on the compile options, variable alignment-dependent shifting and masking. This approach, however, incurs a performance and code size penalty.

Note

Beware of accessing memory-mapped peripheral registers using __packed because the ARM compiler can use multiple memory accesses to retrieve the data. Therefore, nearby locations can be accessed that might correspond to other peripheral registers. When bitfields are used, the ARM compiler currently accesses the entire container, not just the field specified.

Copyright © 2002-2006 ARM Limited. All rights reserved.ARM DUI 0203G
Non-Confidential