[Bug c++/87373] Packed structs are not handled properly on ARM architecture even with misaligned access is enabled

murat.ursavas at gmail dot com gcc-bugzilla@gcc.gnu.org
Mon Oct 1 06:35:00 GMT 2018


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87373

Murat Ursavaş <murat.ursavas at gmail dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |UNCONFIRMED
         Resolution|INVALID                     |---

--- Comment #34 from Murat Ursavaş <murat.ursavas at gmail dot com> ---
I think I've got what's going on. (I know this case turned to a monologue, but
I would like to improve it for the future search references.

In ARM architecture we have one simple linear address space for everything,
flash, RAM and other hardware like peripherals. This makes many things quite
easy.

If you would like to setup a USART, you just write some information on this
address space and you get what you want, like in this case. But If you are like
me, trying to make everything deterministic, you may want to enable
packed-structs. No problem with that. GCC takes care of the rest. It can access
the RAM unaligned anyway as default.

But, one thing can stay under the radar. We see peripheral registers as usual
RAM addresses, but they are not. They may have limitations like no unaligned
access.

In this case with GCC 4.9.3, if I access to the register it uses this:

ldr     r3,[pc,#0x4c]
ldr     r2,[r3,#0x54]
movs    r2,#0x0
orr     r2,r2,#0xb
str     r2,[r3,#0x54]    ;<<<< Important instruction

This part easily sets a 32bit register and everything works as expected.

But after GCC 5+, It uses byte by byte access an uses the instructions below;

ldr     r3,[pc,#0x70]
ldrb.w  r2,[r3,#0x54]
movs    r2,#0x0
orr     r2,r2,#0xb
strb.w  r2,[r3,#0x54]    ;<<<< Important instruction
ldrb.w  r2,[r3,#0x55]
movs    r2,#0x0
strb.w  r2,[r3,#0x55]
ldrb.w  r2,[r3,#0x56]
movs    r2,#0x0
strb.w  r2,[r3,#0x56]
ldrb.w  r2,[r3,#0x57]
movs    r2,#0x0
strb.w  r2,[r3,#0x57]

There is nothing wrong, if it was a normal RAM location. It would set the
register as 0x0000000b. But since this is a peripheral location, and has to be
accessed as aligned, it takes just the first strb.w instruction into
consideration, and leaves further ones useless. 0 - 7bits are OK, but 8-31 bits
are left to decide by entropy. In my case the entropy wants to move the
physical pins to a different location.

I'm not sure whether this is a GCC regression, or must be taken care by the
hardware manufacturer, but this is my conclusion at the end.

So what will be my workaround;

Project wide packed structs are dangerous, I'll remove it from the project
settings and limit it down to necessary structs, leaving others relaxed. This
should make the peripheral access aligned.

P.S: I'm reopening this record for one final evaluation by the GNU team. From
my perspective, this looks like a regression, but it's up to you guys.


More information about the Gcc-bugs mailing list