Simon Kagstrom wrote: > Hi! > > I'm having a compile issue with the Linux kernel for ARM and GCC 4.4.1 > (also occurs in 4.3.3 at least). The code (from orion_nand.c in the > Linux kernel, cooked down) looks like this: > > void *vobb = (void*)0x12345678; > > void orion_nand_read_buf(uint8_t *buf, int len) > { > void *io_base = vobb; > uint64_t *buf64; > int i = 0; > > buf64 = (uint64_t *)buf; > while (i < len/8) { > uint64_t x; > asm ("ldrd\t%0, [%1]" : "=r" (x) : "r" (io_base)); This is wrong. It tells gcc that an address is input to the asm and a uint64_t is returned. But it doesn't tell gcc that some memory at io_base is being used. So, it's legitimate to hoist the asm out of the loop. Add a memory clobber and an earlyclobber: asm ("ldrd\t%0, [%1]" : "=&r" (x) : "r" (io_base)); > GCC is built with crosstool-ng and is called like this: > > arm-unknown-linux-gnueabi-gcc -mcpu=arm926ej-s -c tst.c -o /tmp/tst.o -Os > > the problem does not occur without optimization, but with any -O level. > It can be solved by making the inline asm statement volatile, but the > Linux developers are not happy with that change: > > http://lists.infradead.org/pipermail/linux-mtd/2009-July/026399.html > > > Now, I'm not sure that the inline assembly is completely correct > either. The ldrd instruction > > http://infocenter.arm.com/help/topic/com.arm.doc.ddi0290g/Chddeedh.html > > requires that the destination register should be even (I presume since > it puts the result in a register pair), and maybe that should be > encoded in the output operand constraints? At least GCC 3.4.4 gives me > > Error: destination register must be even -- `ldrd r1,[r2]' > > when compiling this code. I think that is a bug. > So is this a GCC bug or should I head back to the Linux people with it? No-one here is going to fix bugs in gcc 3.4.4. I think you'll need to use an explicit register variable to work round it. Andrew.