内联 C 汇编破坏了它自己的变量

Inline C assembly clobbers its own variables

我想使用内联汇编将两个内存位置读入C变量,然后将两个C变量存储到其他内存位置。我编写的内联代码如下所示:

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");

但是,从我的内联代码生成的程序集似乎不起作用。它将我要存储的变量加载到 r2 和 r3 中,然后立即用我尝试加载的变量破坏它们。从下面的反汇编中可以清楚地看出这一点,我使用 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

我已经阅读了数小时的不同内联汇编教程,并且检查并仔细检查了我的 input/output 约束,但我只是坐在这里挠头。有人能发现我的错误吗?

我正在使用 arm-none-eabi-gcc 版本 4.8.4

您在使用输入之前破坏了 r2r3,并且您忘记通知编译器。你需要一个 & 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.

Source

相关段落隐藏在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.

如果您在装货之前拥有商店,那么您实际上会满足该假设并且一切都会好起来的。既然你不这样做,那么你需要将输出标记为 earlyclobber 操作数,即 "=&l".