The following example comes from ARM linux kernel 2.6.14 ------------------------------------------------------------ #define local_irq_enable() \ ({ \ unsigned long temp; \ __asm__ __volatile__( \ "mrs %0, cpsr @ local_irq_enable\n" \ " bic %0, %0, #128\n" \ " msr cpsr_c, %0" \ : "=r" (temp) \ : \ : "memory", "cc"); \ }) ------------------------------------------------------------ static int __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs) { unsigned int status; int ret, retval = 0; spin_unlock(&irq_controller_lock); if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); status = 0; do { ret = action->handler(irq, action->dev_id, regs); if (ret == IRQ_HANDLED) status |= action->flags; retval |= ret; action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); spin_lock_irq(&irq_controller_lock); return retval; } ------------------------------------------------------------ With arm-linux-gcc 4.0.2, this compiles to: <__do_irq>: mov ip, sp stmdb sp!, {r4, r5, r6, r7, r8, fp, ip, lr, pc} sub fp, ip, #4 ; 0x4 ldr r3, [r1, #4] mov r4, r1 <-- Unnecessary tst r3, #536870912 ; 0x20000000 mov r7, r0 <-- Unnecessary mov r8, r2 <-- Unnecessary bne 1f mrs r3, CPSR ; local_irq_enable bic r3, r3, #128 ; 0x80 msr CPSR_c, r3 1: mov r6, #0 ; 0x0 mov r5, r6 ldr r1, [r4, #16] mov r0, r7 <-- Unnecessary mov r2, r8 <-- Unnecessary mov lr, pc .... .... ie r0, r1 and r2 are copied to callee-saved registers before the inline assembler (and back again afterwards) as if the inline assember were a function call. Inline assembler such as this gets used a lot in the linux kernel...
Do you have a self contained example? I think what you are seeing is a different artifact of a different issue.
Actually I don't think this is a bug: ldr r1, [r4, #16] <--- action->dev_id mov r0, r7 <----- irq mov r2, r8 <----- regs mov lr, pc Call action->handler This is inside a loop so you have to move the registers for the call all the time, now if we striped out the first iteration, then we would not need to do that.
Yes, I think you're absolutely correct. You've also just explained a bug I've been staring at all day ;-) Reading action->dev_id was causing a segfault and I couldn't understand why r0 and r7 in the resulting register dump contained different values... but it must be because the segfault happened on the second time around the loop !! Thanks... and sorry for the noise.
Not a bug.