Android Memory Alignment: ARM vs. x86

Android Memory Alignment: ARM vs. x86


By: Orion R. Granatir

With Google’s recent release of the NDK (r6), it is now possible to build Android applications for x86 processors in addition to ARM. In general, this only involves rebuilding native code to port applications from ARM to x86. However, there are a few pitfalls to avoid.

One difference between x86 and ARM is the memory alignment requirements for data. Let’s look at a simple example:

This example just logs the size and offset of variables in TestStruct. The output for this program isn’t too surprising:

ARM
I/libtestjni( 5025): TestStruct (size: 12)
I/libtestjni( 5025): -- Var1 offset: 0
I/libtestjni( 5025): -- Var2 offset: 4
I/libtestjni( 5025): -- Var3 offset: 8

x86
I/libtestjni( 4175): TestStruct (size: 12)
I/libtestjni( 4175): -- Var1 offset: 0
I/libtestjni( 4175): -- Var2 offset: 4
I/libtestjni( 4175): -- Var3 offset: 8

But now, let’s change TestStruct to the following:

The output is now:

ARM
I/libtestjni( 4675): TestStruct (size: 24)
I/libtestjni( 4675): -- Var1 offset: 0
I/libtestjni( 4675): -- Var2 offset: 8
I/libtestjni( 4675): -- Var3 offset: 16

x86
I/libtestjni( 4079): TestStruct (size: 16)
I/libtestjni( 4079): -- Var1 offset: 0
I/libtestjni( 4079): -- Var2 offset: 4
I/libtestjni( 4079): -- Var3 offset: 12

The 8-byte (64-bit) mVar2 results in different layout for TestStruct. This is because ARM requires 8-byte alignment for 64-bit variables like mVar2. In most cases, this won’t cause problems because building for x86 versus ARM requires a full rebuild.

However, if an application serializes class or structures, this could cause a size mismatch. For example, say you create a save file on an ARM application and it writes TestStruct to a file. If you later load this file on an x86 platform, the class size in the application will be different from the saved file. As you can imagine, similar memory alignment issues can happen for network traffic that expects a specific memory layout.

The GCC compiler option “-malign-double” will generate the same memory alignment on x86 and ARM. However, since the OS was not built with this flag, it will break some OS calls.

You can control the alignment of variables through compiler attributes. So, if we tell GCC to align(8) for mVar2, x86 and ARM will have the same alignment:

The output is now:

ARM
I/libtestjni( 4675): TestStruct (size: 24)
I/libtestjni( 4675): -- Var1 offset: 0
I/libtestjni( 4675): -- Var2 offset: 8
I/libtestjni( 4675): -- Var3 offset: 16

x86
I/libtestjni( 4678): TestStruct (size: 24)
I/libtestjni( 4678): -- Var1 offset: 0
I/libtestjni( 4678): -- Var2 offset: 8
I/libtestjni( 4678): -- Var3 offset: 16

Once you understand the memory alignment difference between x86 and ARM, rebuilding your ARM Android NDK application for x86 should be pretty simple! Go grab the latest NDK and give it a try.


Orion R. Granatir is a senior engineer with Intel’s Visual Computing Software Division [disclosure: Intel is a sponsor of this website]. Prior to that, Orion worked on several PlayStation 3 titles as a senior programmer with Insomniac Games. His most recent published titles are Resistance: Fall of Man and Ratchet and Clank Future: Tools of DestructionHis blogs have previously appeared on Digital Innovation Gazette.

Leave a Comment

There are no comments at this time. Please come back soon

From Our Sponsor

Free
Subscriptions

First Name:
Email: