*
*Home|Chinese|Japanese*About ARM|Forums|Events|News|Employment|Contact Us|Investors*
dotted rule
*ARM - the architecture for the digital worldARM - the architecture for the digital world
search
*
*
***
*MARKETS:PRODUCTS & SOLUTIONS:CONNECTED COMMUNITY:TECHNICAL SUPPORT:DOCUMENTATION*
*
technical support
*
*
****
*.Technical Support
*
*
*>>Home Page*
*
*.Obtaining Support*
*
*.FAQs*
*
**Development Tool FAQs*
**IP FAQs*
**Embedded Software FAQs*
**Artisan Physical IP FAQs (Login Required)*
*
*.Downloads*
*
*.Documentation*
*
*.Training*
*
*.Where To Buy*
*
*.Keil MCU Tools*
*
*.What's New*
*
*.ARM Newsgroups*
*
*.Active Assist On-site Services*
*
*
*
technical support FAQsask ARM*
*

Technical Support Search
*     (Advanced Search)
  FAQs   Documentation   Downloads   Forums

*

 
downarrowAccessing unaligned data from C
Applies to: Compilers, Software Development Toolkit (SDT)

Description
It is sometimes necessary to access unaligned data in memory, in particular for embedded systems. The following describes how this can be doen from C code for ARM or Thumb code.

Like other RISCs, ARM and Thumb processors are designed to efficiently access 'aligned data' (i.e. words which lie on addresses that are multiples of 4, halfwords which lie on addresses that are multiples of 2). This is because memory controllers typically ignore A[1:0] for word accesses and A[0] for halfword accesses.

Using a conventional C pointer (e.g. int *) to read a word, ARM compilers will use an LDR instruction in the generated code. This works as expected when the address is a multiple of 4 (i.e. on a word boundary). However, if the address is not a multiple of 4, then an LDR will return a rotated result rather than performing a true unaligned word load. For more details on how LDR works, see What does the ARM core read/write when using non-aligned addresses?  and the ARM7TDMI datasheet. Generally this rotation is not what the programmer is expecting.

All data accesses can be classified into the following categories:

(1) Natural alignment (eg. words on word boundaries, for example at 0x1000)

ARM's compilers normally align variables and pad structures so that these items are accessed efficiently using the LDR/STR instructions.

(2) Known, but non-natural, alignment (eg. word at address 0x1001)

'Packed' structures used to store records without padding may contain non-natural alignment fields.

a) Declare the entire struct as '__packed'. Each field then inherits the '__packed' qualifier.

__packed struct mystruct {
char c;
short s;
}
As part of its optimization, the ARM compiler will try to deduce the alignment of each field, to improve access to the fields. However, be aware that this optimization is only possible with local structures (and global structures with -zat4), and may not work in every case. A better alternative is to use b) below.

b) Declare non-aligned fields as '__packed'. This is the recommended approach, and the only way of guaranteeing fast access to naturally aligned members within the struct. This also makes it clearer to the programmer which fields are non-aligned, but be careful when adding/deleting fields from the struct.
struct mystruct {
char c;
__packed short s;
}

When a non-aligned member of a packed struct is accessed, the ARM compiler will use multiple aligned memory accesses (LDR/STR/LDM/STM) combined with fixed shifting and masking to access the correct bytes in memory.

For more details on packed structs please see the SDT 2.50 Reference Guide, section 3.1.4

(3) Unknown alignment (eg. a pointer to a word that can be at any address)

This is specified by a pointer to a __packed item, eg.

__packed int *pi; 

In this case, the ARM compilers generate code which correctly accesses the value regardless of the alignment of the pointer. This code generated will be a sequence of byte accesses, or variable alignment-dependent shifting and masking (depending on the compile options) and will therefore incur a performance penalty.

Note that *any* __packed object accessed through a pointer has unknown alignment, even packed structures.

Porting code
Legacy C code for other architectures (e.g. x86 CISC) may perform accesses to unaligned data using pointers which will not work on the ARM. This is non-portable code - such accesses must be identified and corrected to work on RISC architectures which expect aligned data.

Identifying the unaligned accesses can be difficult, because use of load or store with unaligned addresses will give incorrect behavior. But it will be difficult to trace which part of the C source is causing the problem.

ARM processors with full MMUs (e.g. ARM920T) support optional alignment checking where the processor will check every access to ensure it is correctly aligned. The MMU will raise a data abort if an incorrectly aligned access occurs.

Some ARM partners using simple cores such as the ARM7TDMI have implemented alignment-checking for their ASIC/ASSP. This can be done with an additional hardware block external to the ARM core, which monitors the access size and the least significant bits of the address bus for every data access. The ASIC/ASSP can be configured to raise the ABORT signal in the case of an unaligned access. ARM recommends that such logic is included on ASIC/ASSP devices where code will be ported from other architectures.

If the system is configured to abort on unaligned accesses, a data abort exception handler should be installed. When an unaligned access occurs, the data abort handler will be entered - this can identify the erroneous data access instruction which is located at (r14-8).

Once identified, the data access must be fixed by changes to the C source. These changes can be made conditional using the following technique:

#ifdef __ARMCC
#define PACKED __packed
#else
#define PACKED
#endif
:
PACKED int *pi;
:

It is best to minimise accesses to unaligned data because of code size and performance overheads.

Be careful when accessing memory-mapped peripherals using __packed, because the ARM compilers can use multiple memory accesses to retrieve the data, and may also access nearby locations which might correspond to other peripheral registers. When bitfields are used, the ARM compiler currently accesses the entire container, not just the field specified.

For information on big/little endianness and how it affects data accesses, please see How does Little/Big Endian mode affect aligned/unaligned addressing and Application Note 61: Big and Little Endian Byte Addressing, in the ARM Application Notes.

Note the ARM compiler may use an LDR with an unaligned address to perform a halfword load if the "-arch 3" command-line option is used. See armcc/tcc: Unaligned loads and the -za1 option.






back to top

*
**
*4 dots*Other ARM Websites
*
shadow *LEGAL STATEMENTshadow