http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46483

Mikael Pettersson <mikpe at it dot uu.se> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |mikpe at it dot uu.se

--- Comment #5 from Mikael Pettersson <mikpe at it dot uu.se> 2010-11-15 
21:28:12 UTC ---
When I run the original test case on armv5tel-linux-gnueabi it works, but
causes the Linux kernel to log an unaligned access in the binary just executed,
which it fixed up.

The original observation
> BUILT-IN MEMCPY TO 04016bd7:  78 56 34 12 00 00 00
> USER-DEF MEMCPY TO 04016bd7:  ff ff ff 78 56 34 12
is then probably explained by the arm-elf environment (bare metal?) disabling
and ignoring alignment faults, which causes the processor to access different
locations than normally expected.

In the simpler test case I attached we can see how gcc totally ignores
knowledge about mis-alignment when expanding __builtin_memcpy:

> /* pr46483.c */
> 
> struct unaligned_int {
>     char dummy;
>     unsigned int number;
> } __attribute__((packed));
> 
> void set_by_memcpy(struct unaligned_int *p, unsigned int x)
> {
>     __builtin_memcpy(&p->number, &x, sizeof(unsigned int));
> }

for this gcc-4.5 generates

> set_by_memcpy:
>         @ args = 0, pretend = 0, frame = 0
>         @ frame_needed = 0, uses_anonymous_args = 0
>         @ link register save eliminated.
>         str     r1, [r0, #1]
>         bx      lr

which does an int-sized write to &p->number (r0+1), which isn't int-aligned.

For the equivalent plain assignment:

> void set_by_assignment(struct unaligned_int *p, unsigned int x)
> {
>     p->number = x;
> }

gcc-4.5 generates

> set_by_assignment:
>         @ args = 0, pretend = 0, frame = 0
>         @ frame_needed = 0, uses_anonymous_args = 0
>         @ link register save eliminated.
>         mov     ip, r1, lsr #8
>         mov     r2, r1, lsr #16
>         mov     r3, r1, lsr #24
>         strb    r1, [r0, #1]
>         strb    ip, [r0, #2]
>         strb    r2, [r0, #3]
>         strb    r3, [r0, #4]
>         bx      lr

so here it does know about the misalignment and avoids misaligned int-sized
writes.

Finally let's ask gcc about the known alignment of an unaligned_int:

> unsigned int alignof_p(struct unaligned_int *p)
> {
>     return __alignof__(p);
> }
> 
> unsigned int alignof_p_number(struct unaligned_int *p)
> {
>     return __alignof__(p->number);
> }

for this it generates

> alignof_p:
>         @ args = 0, pretend = 0, frame = 0
>         @ frame_needed = 0, uses_anonymous_args = 0
>         @ link register save eliminated.
>         mov     r0, #4
>         bx      lr
...
> alignof_p_number:
>         @ args = 0, pretend = 0, frame = 0
>         @ frame_needed = 0, uses_anonymous_args = 0
>         @ link register save eliminated.
>         mov     r0, #1
>         bx      lr

so clearly gcc knows that the number field is only byte-aligned.

gcc-4.4.5 generates similar bogus code for __builtin_memcpy.  Current 4.6
however converts the __builtin_memcpy to a call to the memcpy library routine.

Reply via email to