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.