内联C程序集破坏了它自己的变量

时间:2016-05-19 17:54:01

标签: c assembly arm inline-assembly cortex-m

我想使用内联汇编将两个内存位置读入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

我已经阅读了几个小时不同的内联汇编教程,我已经检查过&amp;仔细检查了我的输入/输出限制,我只是坐在这里挠挠脑袋。有人能抓住我的错误吗?

我使用的是arm-none-eabi-gcc版本4.8.4

2 个答案:

答案 0 :(得分:3)

相关段落隐藏在the extended asm documentation

的中间
  

对所有不能与输入重叠的输出操作数使用&约束修饰符(请参阅Modifiers)。否则,GCC可以将输出操作数分配到同一寄存器中作为无关输入操作数,前提是汇编代码在产生输出之前消耗其输入。如果汇编代码实际上包含多个指令,则此假设可能为假。

如果您在装载之前有商店,那么您实际上会满足这个假设,一切都会好的。既然你没有,那么你需要将输出标记为早期操作数,即"=&l"

答案 1 :(得分:2)

您在使用输入之前已经破坏了???list [] = [[]] list (x:xs) = [(x,c) : ys | ys <- list xs, c <- [C,I,U] ] ,而您忘记通知编译器。你需要一个r2早期修补符修饰符:

  

在所有输出操作数上使用'&amp;'约束修饰符(请参阅修饰符)   不得与输入重叠。否则,GCC可能会分配输出   操作数与同一寄存器中的无关输入操作数相同   假设汇编代码之前消耗了它的输入   产出产出。如果汇编代码,这个假设可能是错误的   实际上由多个指令组成。

Source