http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60918
Bug ID: 60918 Summary: [mips] unaligned memory copy with LWL/LWR Product: gcc Version: 4.8.2 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: Alex.Schoenberger at ies dot tu-darmstadt.de * GCC configuration: --with-newlib --without-headers \ --enable-multilib --disable-werror \ --enable-languages="c" \ --disable-shared \ --disable-nls --disable-threads --disable-hosted-libstdcxx --disable-libssp \ --target=mips-elf --prefix=$PATH_TO_MIPS --with-gnu-ld --with-gnu-as \ --with-mprf=$PATH_TO_MIPS --with-gmp=$PATH_TO_MIPS --with-mpc=$PATH_TO_MIPS * GCC call flags: -EB -O2 -Wall -mips1 -c -s -msoft-float * no error messages * source code consists of two files. The generated assemling code differs if I compose them * mem.c - implementation of copy memory: void * memcpy( void * destination, const void * source, int num ){ while(num){ --num; ((unsigned char *)destination)[num] = ((unsigned char *)source)[num]; } return destination; } * error.c - call of memcpy #include "mem.h" typedef struct { unsigned int field; } struct_t; int main() { unsigned int * address = (unsigned int *) 0x123c; struct_t * var1 = (struct_t *) address[0]; // this emulates malloc -> unknown return address struct_t * var2 = (struct_t *) address[1]; var1->field = 0x12345678; memcpy( var2, var1, sizeof(struct_t)); return 0; } * generated assembler code, compiler replaces "memcpy"-call with LWL/LWR instructions: Disassembly of section .text: 00000000 <.text>: 0: 8c04123c lw a0,4668(zero) 4: 3c021234 lui v0,0x1234 8: 24425678 addiu v0,v0,22136 c: 8c031240 lw v1,4672(zero) 10: ac820000 sw v0,0(a0) 14: 88850000 lwl a1,0(a0) -> first access: LWL command 18: 00001021 move v0,zero 1c: 98850003 lwr a1,3(a0) -> second access: LWR command 20: 00000000 nop 24: a8650000 swl a1,0(v1) -> for store operation the same procedure 28: 03e00008 jr ra 2c: b8650003 swr a1,3(v1) -> second store command 30: 10c00007 beqz a2,0x50 -> here "memcpy" starts 34: 00801021 move v0,a0 38: 24c6ffff addiu a2,a2,-1 3c: 00a61821 addu v1,a1,a2 40: 90670000 lbu a3,0(v1) 44: 00461821 addu v1,v0,a2 48: 14c0fffb bnez a2,0x38 4c: a0670000 sb a3,0(v1) 50: 03e00008 jr ra 54: 00000000 nop * this leads to erronous run: if my memory (big endian) content is: @address: 11 22 33 44 55 66 77 88 lets assume "a1" contains zero in the beginning lwl a1, 0(a0) -> a1 = 0x11220000 lwr a1, 3(a0) -> a1 = 0x11226677 the memory content is copied erronous, values 33[3(a0)], 44[4(a0)] and 55[5(a0)] are ignored