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.