Inconsistent handling of unaligned read

Asked by Bjorn Blixhavn on 2017-04-27

The following occurs in Atmel Studio7, with the ARM GNU Toolchain 5.3.1 and an ARM M0+ target.
The -Wall and -Wextra compiler flags are set, but no warning or error message is given.

With no optimization, the c code
    adclin = (*(volatile uint16_t*) 0x00806023);
compiles to
    dc8e: 4b2f ldr r3, [pc, #188] ; (dd4c <InitADC+0xc4>)
    dc90: 881b ldrh r3, [r3, #0]
which is an unaligned half-word read, and causes a HardFault exception.

With Optimization(-O1), the compiled code is
    9406: 4a24 ldr r2, [pc, #144] ; (9498 <InitADC+0x94>)
    9408: 7811 ldrb r1, [r2, #0]
    940a: 7853 ldrb r3, [r2, #1]
    940c: 021b lsls r3, r3, #8
    940e: 430b orrs r3, r1
which performs two byte reads and assembles the half word, thus avoiding the exception.

Is this a compiler bug? I would expect the compiler to be consistent, and to either handle the case or issue an error message.

Question information

Language:
English Edit question
Status:
Solved
For:
GNU ARM Embedded Toolchain Edit question
Assignee:
No assignee Edit question
Solved by:
Thomas Preud'homme
Solved:
2017-04-28
Last query:
2017-04-28
Last reply:
2017-04-27

Hi Bjorn,

Casting to uint16_t * is equivalent to tell the compiler "this is a pointer to 16-bit integer and is thus 16-bit aligned". The compiler does not emit any warning because you explicitely tell it that you know what you are doing.

Best regards.

Bjorn Blixhavn (l-bjorn) said : #2

Hi Thomas,
The compiler gives warnings in other cases when you presumably know what you are doing, like using assignment as truth value, or testing unsigned values for being negative.
But what strikes me as odd is that optimization fixes the problem. I thought optimization was about reducing size or time.
Anyway, thanks for your answer, I will get on with my work.

Best regards,
Bjørn

Bjorn Blixhavn (l-bjorn) said : #3

Thanks Thomas Preud'homme, that solved my question.

Hi Bjorn,

Cast really need to be understood as a hint to the compiler. It's basically a way to suppress warning or errors. I agree it's unfortunate that there is no way to do an assignment of an address to pointer with basic alignment check. I tried casting it to void * but that also suppress any warning.

Best regards.

Leo Havmøller (leh-p) said : #5

The KEIL ARM compiler has a __packed keyword, to tell the compiler that a pointer points to unaligned memory: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html
Unfortunately gcc does not have anything similar.