当前位置: 首页 > 知识库问答 >
问题:

重写GCC内联程序集,使其不需要易失性或内存重写

卢志业
2023-03-14
// do stuff with the input Foo structure and write the result to the 
// output Bar structure.
static inline void MemFrob(const struct Foo* input, struct Bar* output) {
    register const Foo* r0 asm("r0") = input;
    register Bar* r1 asm("r1") = output;

    __asm__ __volatile__(
        "svc #0x0f0000 \n\t"
        : "+r" (r0), "+r" (r1)
        :
        : "r2", "r3", "cc", "memory"
        );
}

对于这种特定的情况,目标平台是一个ARM7系统,代码正在用GCC5.3.0进行编译。正在执行的系统调用具有与C函数调用相同的调用约定。经过一些尝试和错误,我得到了上面的“工作”,但我还不相信它是正确的,并且会一直工作,服从于优化编译器的奇思妙想。

我希望能够删除“内存”clobber,并确切地告诉GCC哪些内存将被修改,但是GCC扩展的Asm文档讨论了如何为特定寄存器赋值,然后是内存约束,但如果它们可以合并,则不讨论。到目前为止,从上面的示例中删除“memory”clobber可能会导致GCC在继续的代码中不使用输出。

我还希望能够在不使用输出的情况下删除volatile。但是到目前为止,从上面的示例中删除volatile会导致GCC根本不发出程序集。

共有1个答案

赵景曜
2023-03-14

长话短说:这就是“m”约束的用途。通常,如果您正在使用volatile__volatel__,并使用asm,这是因为您的代码中存在错误。编译器的主要工作之一是流分析,所以只要你给它足够的信息来做正确的流分析,一切都会正常工作。

这里有一个固定版本:

void MemFrob(const struct Foo* input, struct Bar* output) {
    register const Foo* r0 asm("r0") = input;
    register Bar* r1 asm("r1") = output;
    __asm__ (
        "svc #0x0f0000"
        : "=m"(*r1) // writes data to *output (but does not read)
        : "m"(*r0), // reads data in *input
          "l"(r0), "l"(r1) // This is necessary to ensure correct register
        : "r2", "r3", "cc"
        );
}

您可以在https://gcc.godbolt.org/(推荐-o2编译器选项)上测试它。输出如下:

svc #0x0f0000
bx lr
 类似资料:
  • 我对下面的代码段有一个问题。结果可能有一个结果[0,1,0](这是用JCStress执行的测试)。那么这是怎么发生的呢?我认为数据写入(data=1)应该在Actor2(guard2=1)中写入到guard2之前执行。我说得对吗?我问,因为很多时候我读到挥发物周围的说明没有重新排序。此外,根据这一点:http://tutorials.jenkov.com/java-concurrency/vola

  • 这里是一个虚拟的*z++=*x++**y++指令。请注意,x、y和z指针寄存器必须指定为输入/输出,因为asm会修改它们。 在第一个示例中,在输入操作数中列出和有什么意义?同一份文件指出: 特别是,如果不将输入操作数指定为输出操作数,就无法指定输入操作数被修改。

  • 有没有人要对我说或评论? 跟随生成的程序集 多亏了弄臣的解决之道:

  • 我试图通过Composer在客户端的Magento 2上安装一个扩展,但我遇到了旧的PHP内存溢出错误。 我的客户端由Bluehost托管,不幸的是,这意味着我不能直接进入并更改php.ini中的内存限制,因为它是只读的,而且它们的cPanel MultiHP ini编辑器不会影响SSH。我的客户机已经与Bluehost联系过,他们被告知Bluehost不允许更改SSH内存限制,但是,我的客户机最

  • 换句话说,你是可以平等地将它们视为存储空间,还是应该坚持将它们用于特定目的?

  • a)为什么除了“00”之外还有其他输出? b)如何修改代码以便始终打印“00”。 对于a)我的回答是:在没有任何volatile/同步构造的情况下,编译器可以重新排序一些指令。特别是“this.initialint=val;”和“this.flag=true;”可以切换,这样就可以发生这种情况:线程都启动了,t1充电在前面。给定重新排序的指令,它首先设置flag=true。在它到达“this.in