Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
内联C程序集将自己的变量替换掉_C_Assembly_Arm_Inline Assembly_Cortex M - Fatal编程技术网

内联C程序集将自己的变量替换掉

内联C程序集将自己的变量替换掉,c,assembly,arm,inline-assembly,cortex-m,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, #

我想使用内联汇编将两个内存位置读入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
us32=(uint32_t)us;
c8e:6BB ldr r3,[r7,#56];0x38
c90:637b str r3[r7,#52];0x34
__asm\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
这4条指令加载我要写入内存的变量
进入r2和r3
c92:2207 movs r2,#7
c94:4b39 ldr r3[pc,#228];(d7c)
c96:6819 ldr r1,[r3,#0]
c98:6b7b ldr r3[r7,#52];0x34
轰!r2和r3已经被击落,它们不再包含
;;我要写入的值(常量#7,在us32中为无符号)。
;;; 
我想读的数据确实是由r1+16和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
我读了几个小时不同的内联汇编教程,我检查了输入/输出约束,我只是坐在这里挠头。有人能抓住我的错误吗


我使用的是
arm-none-eabi-gcc
version 4.8.4

您在使用输入之前敲打了
r2
r3
,而您忘记了通知编译器。您需要一个
早期敲打修改器:

在所有输出操作数上使用“&”约束修饰符(请参见修饰符) 这不能与输入重叠。否则,GCC可能会分配输出 与不相关的输入操作数位于同一寄存器中的操作数 假设汇编器代码在 产生输出。如果汇编程序代码 实际上由多条指令组成


< P>相关段落隐藏在中间:

使用
约束修改器(请参见)在所有输出操作数上,不能与输入重叠。否则,GCC可能会将输出操作数分配到与不相关的输入操作数相同的寄存器中,前提是汇编代码在生成输出之前消耗其输入。如果汇编代码实际上由多条指令组成,则此假设可能是错误的


如果在加载之前就有了存储,那么实际上就满足了这个假设,一切都会好起来。因为没有,所以需要将输出标记为earlyclobber操作数,即
“=&l”

哇……这完全解决了我的问题。我真不敢相信,在阅读了所有的文章之后,我竟然找不到这一点。令我非常惊讶的是,gcc并没有自动假定&的语法。@johnny\u boy:GNU C内联asm语法是为包装一条无法让编译器发出的指令而设计的,这就是为什么默认设置不是当然。通常最好让编译器尽可能多地执行。有关GNU C内联asm指南和Q&a的链接集,请参阅。它们都使用x86,但这些概念同样适用于ARM。编写GNU C内联asm是学习asm最难的方法,因为它很容易使约束出错。@johnny_boy在大多数情况下,您可能需要任何inpu如果替代方法意味着溢出到asm周围的堆栈中,则尽可能将t寄存器重新用于输出寄存器。您的代码不会阻塞标志,因此不需要
“cc”
阻塞器。如果使用内存输出操作数,还可以避免
“memory”
阻塞。(可以像clobber文档建议的那样使用覆盖所有存储的伪结构,也可以使用每个存储的单个内存操作数让gcc选择寻址模式。
[命名]“r”(操作数)
在有多个操作数时强烈建议使用,以避免在添加更多重新编号时出现混淆。)您可以对同一寄存器使用
strd
两次,用一条指令执行前两个存储吗?如果没有,您可以重新排序,在一个strd中执行#10和#14存储,但在顺序CPU上效果会更差。@PeterCordes“cc”标志是我编写的一些其他代码留下的;我将删除它们。感谢您提供有关命名寄存器和结构的提示。此外,我不能执行strd,因为我使用的是不支持该指令的m0+。