内联C程序集将自己的变量替换掉
我想使用内联汇编将两个内存位置读入C变量,然后将两个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, #
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+。