问题描述
是否有可能重写或改善这一功能不需要挥发性或通用内存撞在其内联汇编?
Is it possible to rewrite or improve this function to not require volatile or a generic memory clobber in its inline assembly?
// 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系统和code正在使用GCC 5.3.0编译。正在执行系统调用具有相同的调用约定的C函数调用。一些试验和错误之后,我来到了高于该工程,但我还不相信这是正确的,会一直工作,受到了优化编译器的冲动和幻想。
For this specific situation, the target platform is an ARM7 system, and the code is being compiled with GCC 5.3.0. The system call being performed has the same calling convention as a C function call. After some trial and error, I've arrived at the above which "works" but I am not yet confident that it is correct and will always work, subject to the whims and fancies of the optimizing compiler.
我希望能够删除的记忆揍告诉GCC到底是哪内存将被修改,但延长ASM文档海湾合作委员会讨论了如何将值分配给特定的寄存器,然后内存的限制,但如果它们都可以被组合。截至目前,除去上面的例子中记忆撞会导致GCC不使用程序code的输出。
I'd like to be able to remove the "memory" clobber and tell GCC exactly which memory will be modified, but the GCC Extended Asm documentation discusses how to assign values to specific registers, and then memory constraints, but not if they both can be combined. As of now, removing the "memory" clobber from the above example can cause GCC to not use the output in proceeding code.
我还希望能够除去挥发性在未使用的输出的情况下。但截至目前,从上面的例子中除去挥发导致GCC不发出组装的。
I'd also like to be able to remove the volatile in the cases where the output is not used. But as of now, removing volatile from the above example causes GCC to not emit the assembly at all.
通过移动code到外部编译单元添加额外的内联汇编手动移动系统调用的参数到R0 / R1或取消内联被浪费的变通办法我宁愿避免的。
Adding additional inline assembly to move the system call parameters into r0/r1 manually or un-inlining by moving the code to an external compilation unit are wasteful workarounds that I'd much rather avoid.
推荐答案
长话短说:这是M
约束是什么。通常情况下,如果你使用挥发性
或 __挥发性__
与 ASM
,这是因为在你的code错误。一个编译器的主要工作之一就是流分析,所以只要你给它足够的信息做正确的流量分析,一切都将正常工作。
Long story short: this is what the "m"
constraint is for. Usually, if you are using volatile
or __volatile__
, with asm
, it is because there is an error in your code. One of the compiler's main jobs is flow analysis, so as long as you give it enough information to do the correct flow analysis, everything will work correctly.
下面是一个固定的版本:
Here is a fixed version:
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"
);
}
您可以测试它在( -O2
编译器选项推荐)。输出如下所示:
You can test it on https://gcc.godbolt.org/ (-O2
compiler options recommended). The output is as follows:
svc #0x0f0000
bx lr
显然,内联时,应减少到只是一个指令。
Obviously, when inlined, it should reduce to just the one instruction.
不幸的是,我无法弄清楚如何使用内联ARM汇编,除上述这是一个有点笨拙的方法之外时指定特定的寄存器。
Unfortunately, I couldn't figure out how to specify specific registers when using inline ARM assembly, other than the method above which is a bit clumsy.
这篇关于重写GCC内联汇编为不需要挥发或内存撞的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!