Reputation: 1496
I want to use inline assembly to read two memory locations into C variables and then store two C variables to other memory locations. The inline code that I have written looks like this:
unsigned int us32 = (uint32_t)us;
__asm__ __volatile__("ldr %1, [%4, #0x10]\r\n" //read my 2 memory locations
"ldr %0, [%4, #0x18]\r\n"
"str %2, [%4, #0x14]\r\n" //write my 3 memory locations
"str %2, [%4, #0x18]\r\n"
"str %3, [%4, #0x10]\r\n"
: "=l" (leftover_time), "=l" (rollflag)
: "l" (us32), "l" (ena), "l" (s)
: "memory", "cc");
The assembly that is generated from my inline code, however, doesn't seem to work. It loads the variables that I want to store into r2 and r3 and then promptly clobbers them with the variables I am trying to load. This is pretty clear from the disassembly below, which I got using arm-none-eabi-objdump
us32 = (uint32_t)us;
c8e: 6bbb ldr r3, [r7, #56] ; 0x38
c90: 637b str r3, [r7, #52] ; 0x34
__asm__ __volatile__("ldr %1, [%4, #0x10]\r\n"
;;; These 4 instructions load the variables I want to write to memory
;;; into r2 and r3
c92: 2207 movs r2, #7
c94: 4b39 ldr r3, [pc, #228] ; (d7c <reschedule+0x16c>)
c96: 6819 ldr r1, [r3, #0]
c98: 6b7b ldr r3, [r7, #52] ; 0x34
;;; BOOM!! r2 and r3 have been clobbered, they no longer contain the
;;; values that I want to write (a constant #7 and unsigned in us32).
;;;
;;; The data that I want to read is indeed pointed by r1 + 16 and r1 + 24
c9a: 690b ldr r3, [r1, #16]
c9c: 698a ldr r2, [r1, #24]
c9e: 614b str r3, [r1, #20]
ca0: 618b str r3, [r1, #24]
ca2: 610a str r2, [r1, #16]
ca4: 633a str r2, [r7, #48] ; 0x30
ca6: 62fb str r3, [r7, #44] ; 0x2c
I've read different inline assembly tutorials for hours and I've checked & double-checked my input/output constraints and I'm just sitting here scratching my head. Can someone catch my mistake?
I am using arm-none-eabi-gcc
version 4.8.4
Upvotes: 2
Views: 687
Reputation: 20974
The relevant paragraph is hidden right in the middle of the extended asm documentation:
Use the
&
constraint modifier (see Modifiers) on all output operands that must not overlap an input. Otherwise, GCC may allocate the output operand in the same register as an unrelated input operand, on the assumption that the assembler code consumes its inputs before producing outputs. This assumption may be false if the assembler code actually consists of more than one instruction.
If you had the stores before the loads, you would actually meet that assumption and everything would be fine. Since you don't, then you need to mark the outputs as earlyclobber operands, i.e. "=&l"
.
Upvotes: 3
Reputation: 58782
You clobbered r2
and r3
before consuming the inputs and you forgot to inform the compiler. You need an &
early-clobber modifier for them:
Use the ‘&’ constraint modifier (see Modifiers) on all output operands that must not overlap an input. Otherwise, GCC may allocate the output operand in the same register as an unrelated input operand, on the assumption that the assembler code consumes its inputs before producing outputs. This assumption may be false if the assembler code actually consists of more than one instruction.
Upvotes: 2