SoC
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
  • Arm Cortex M3
  • Contact
Reading: Use of Address of Unaligned Structure Member
SUBSCRIBE
SoCSoC
Font ResizerAa
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Search
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Have an existing account? Sign In
Follow US
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
© S-O-C.ORG, All Rights Reserved.
Arm

Use of Address of Unaligned Structure Member

Javier Massey
Last updated: September 14, 2023 12:31 am
Javier Massey 7 Min Read
Share
SHARE

Accessing members of a structure that is not aligned to the natural alignment of its members can lead to unaligned memory accesses. This can cause performance issues and even runtime errors on some architectures like ARM that do not support unaligned accesses natively. However, there are techniques to safely use the address of an unaligned structure member.

Contents
What is Structure AlignmentIssues with Unaligned AccessesAligning StructuresAccessing Unaligned Structure Members1. Use uint8_t* Pointer2. Use memcpy3. Load Entire Structure then Access MembersUsing Address of Unaligned Members1. Pointer Cast to uint8_t*2. memcpy Address to Aligned Local3. Union PointerMitigations on ARMConclusion

What is Structure Alignment

Structure alignment refers to how the members of a struct are arranged in memory. For optimal performance, compilers will insert padding between struct members to align each member to its natural alignment boundary. For example, a 4-byte integer would be aligned to a 4-byte boundary. This enables the CPU to access the data efficiently in a single load/store instruction.

The natural alignment of a data type is usually its size (in bytes). So a 4 byte int would have an alignment of 4, an 8 byte double would have an alignment of 8, etc. Compilers ensure each struct member is aligned properly, which may require padding between members.

Issues with Unaligned Accesses

If a structure is not aligned properly, then accessing its members will cause unaligned accesses. This can lead to several issues:

  • Performance degradation – Unaligned accesses may require multiple memory transactions instead of just one. This can lower performance.
  • Unaligned access errors – Some architectures like ARM do not support unaligned accesses natively in hardware. This will cause a runtime error or fault.
  • Undefined behavior – C/C++ standards allow compilers to assume aligned accesses. Unaligned access can lead to unexpected results.

Aligning Structures

To avoid issues with unaligned accesses, structures should be aligned properly. There are a few ways to do this in C/C++ code:

  • Let the compiler handle alignment automatically by default. Compilers will align members to prevent unaligned accesses.
  • Use #pragma pack to specify packing rules for a struct declaration.
  • Use alignas specifier if available in C++11 and later to force a struct to be aligned to a certain boundary.
  • Manually insert padding fields to align members.

Ensuring the struct has proper alignment prevents unaligned accesses to members later when the struct is used.

Accessing Unaligned Structure Members

There are times when a structure may be unaligned, for example when:

  • Interfacing with a hardware register interface that requires specific fixed layout.
  • Reading network packets or files formats that have fixed unaligned layouts.
  • Casting an unaligned buffer to a structure type.

In these cases, we cannot change the definition of the structure itself to be aligned properly. However, we can still safely access unaligned structure members in a few different ways:

1. Use uint8_t* Pointer

Cast the structure pointer to a uint8_t* pointer. Then use pointer arithmetic to access each unaligned member. This treats the struct as a byte array rather than a properly aligned struct. struct unaligned_struct { uint32_t a; uint8_t b; uint16_t c; }; void func(struct unaligned_struct* s) { uint8_t* bytes = (uint8_t*) s; uint32_t a = *(uint32_t*)bytes; bytes += 4; uint8_t b = *bytes; bytes++; uint16_t c = *(uint16_t*)bytes; }

2. Use memcpy

Use memcpy to copy each unaligned member into a local aligned variable. The memcpy will handle the unaligned access. void func(struct unaligned_struct* s) { uint32_t a; memcpy(&a, &s->a, sizeof(a)); uint8_t b; memcpy(&b, &s->b, sizeof(b)); uint16_t c; memcpy(&c, &s->c, sizeof(c)); }

3. Load Entire Structure then Access Members

Use memcpy to load the entire unaligned structure into an aligned local stack variable. Then access the aligned copy. void func(struct unaligned_struct* s) { struct aligned_struct { uint32_t a; uint8_t b; uint16_t c; } temp; memcpy(&temp, s, sizeof(temp)); uint32_t a = temp.a; uint8_t b = temp.b; uint16_t c = temp.c; }

Using Address of Unaligned Members

Sometimes we need a pointer directly to an unaligned structure member. This should be avoided on architectures like ARM. But can be done carefully using a few methods:

1. Pointer Cast to uint8_t*

Cast the address to a uint8_t* and offset to the member address: uint8_t* ptr = (uint8_t*)&s->b;

2. memcpy Address to Aligned Local

Use memcpy to copy the member address into an aligned local pointer variable: uint32_t* aligned_ptr; memcpy(&aligned_ptr, &s->a, sizeof(aligned_ptr));

3. Union Pointer

Use a union to store the address in an aligned way: union { uint32_t align; uint32_t* ptr; } u; u.ptr = &s->a;

Mitigations on ARM

The ARM architecture generally does not support unaligned accesses in hardware. But there are some mitigations and techniques to allow unaligned access on ARM:

  • Some ARM cores implicitly support unaligned accesses using multiple memory transactions. This hurts performance.
  • The ARMv6 architecture added support for halfword unaligned accesses using the LDRH/STRH instructions.
  • The __packed qualifier tells the compiler a struct does not require alignment. This enables unaligned access to those structs.
  • The __attribute__((packed)) attribute can be used on individual struct declarations to ignore alignment.
  • Some compilers provide options like -munaligned-access to allow unaligned accesses by emulating them in software.

However, unaligned accesses on ARM still remain slower than naturally aligned access. Avoid whenever possible by properly aligning structures.

Conclusion

Unaligned structure members can be safely accessed in C/C++ using pointer casts, memcpy, or temporary aligned copies. This prevents unaligned access issues. Pointers to unaligned members can also be obtained with careful casting or type punning. Overall, maintaining proper structure alignment is ideal, but unaligned structures can be supported with some extra care on architectures like ARM.

Newsletter Form (#3)

More ARM insights right in your inbox

 


Share This Article
Facebook Twitter Email Copy Link Print
Previous Article Unaligned Access Error
Next Article Is the arm processor the same as the ESP32?
Leave a comment Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

2k Followers Like
3k Followers Follow
10.1k Followers Pin
- Sponsored-
Ad image

You Might Also Like

What is the ARM Calling Convention?

The ARM calling convention refers to the standard procedure used…

9 Min Read

Lazy Context Switching

Lazy context switching is a technique used in operating systems…

7 Min Read

What is Bit-Band memory in Arm Cortex-M series?

Bit-Band is a feature of the memory architecture in Arm…

6 Min Read

Does Apple use ARM chips?

Yes, Apple does use ARM-based chips in many of its…

6 Min Read
SoCSoC
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
Welcome Back!

Sign in to your account