Sign in to follow this  
floatingwoods

Data alignment on ARM processors

Recommended Posts

Hello,

 

I recently faced a problem with some C code, on ARM processors, where data alignment is of importance. I typically have following 2 scenarios:

float value=doLittleBigEndianConversion(((int*)(ucharPtr+offset))[0]);

and

((int*)(ucharPtr+offset))[0]=someIntValue;

Depending on the offset, I get some crashes. So the solution to scenario 1 is (for instance):

float value;
memcpy (&value,ucharPtr+offset,sizeof(float));
value=doLittleBigEndianConversion(value);

Which solves the alignment problem. My question is now: How can I fix the scenario2 code, so that it also works on ARM processors?

 

Thanks for any insight!

Share this post


Link to post
Share on other sites

On ARM processor the alignment of data is important. It can read/write much faster at aligned positions. So 2-byte long value should be on an even address, and a 4-byte long value should be on an address dividable by 4. There are codes for unaligned read/write but they are different, longer and slower. The compiler must find out which code has to be used, and generally it does a very good job finding it out, but a few times fails.

 

These failed cases always contain a reinterpret_cast. In your case this is the C-style (int*) casting. That kind of casting is typically used in loading/saving data, or receiving/sending data through network. In other places it is typically just bad design, and should be avoided.

 

So I recommend you to concentrate all your code that uses reinterpret_cast into one or few classes, and handle the problem there.

 

And you can create a function for this kind of reading/writing similar to your doLittleBigEndianConversion. Like this:

float value = doLittleBigEndianConversion(doUnalignedReading(reinterpret_cast<int*>(ucharPtr + offset));

In that function just use the memcpy trick or read the data byte by byte and assemble it with |.

Share this post


Link to post
Share on other sites

*((unsigned char*)(&result)) = *offset;

Watch out for compiler optimisations breaking code like this (called type punning). It breaks the language aliasing rules. See this link:

http://stackoverflow.com/questions/20922609/why-does-optimisation-kill-this-function/20956250#20956250


Except this is irrelevant since the char-types are explicitly allowed to do this.

Share this post


Link to post
Share on other sites

The best way to solve this problem really depends on the details.

 

Given what you have posted: since you have to perform big/little endian reordering anyway, you can get de-aliasing for free if you use a macro instead of a function as-long-as you write the macro to access the data byte-by-byte.

 

If the function adapts to the system/data then you need a corresponding no-swap macro that is hard-coded to move 4 bytes (that will be much faster than invoking memcpy for such a small amount of data).

Share this post


Link to post
Share on other sites

I'm curious, why are you performing endian conversions?

 

Just about every vendor I can think of runs their ARM chips in little-endian mode, and since the end of Apple's PowerPC era, the majority of applications don't even use network byte order either.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this