在GCC手册中,部分6.43.2.5 Extended Asm - Clobbers,在“记忆”撞的解释寄存器,被提及,避免冲洗寄存器一招:避免冲洗内存访问(GCC内联汇编)
如果你知道存储器的大小在编译时被访问,可以指定一个存储器输入这样的:
{"m"(({ struct { char x[10]; } *p = (void *)ptr ; *p; }))}
(假设你访问的10个字节的字符串。)
我想我理解这个想法,但是我不完全清楚如何使用它,以及这个诀窍会产生什么影响 - 除了向GCC提供更多类型的信息之外。 最重要的三个问题就出来了:
- 我还以此为输出或输入/输出操作数和修改数据?
- 如果我使用这个技巧,我是否仍然需要“内存”clobber?
我想我不这样做,因为我宣称内存块是输入/输出,但我不确定。 - 只有在访问内存时,我可以安全地删除所需的
volatile
限定符吗?
我想我可以,因为它会被声明为输出。
因为我们喜欢的例子:这段代码是否有意义,它是合法的吗?它似乎工作。
#include <iostream>
#include <cstdint>
void add_assembly(std::uint64_t * x) {
struct memory { std::uint64_t data[2]; } * p = reinterpret_cast<memory*>(x);
__asm__ (
"addq $1, %[x] \t\n"
"addq $5, 8%[x] \t\n"
: [x] "+m" (*p) // Bonus question: Why don't I need a "&" here?
: "m" (*p)
: "cc"
);
}
int main() {
std::uint64_t x[2];
x[0] = 3000;
x[1] = 7253;
std::cout << "before: " << x[0] << " " << x[1] << std::endl;
add_assembly(&x[0]); // add 1 to x[0], add 5 to x[1]
std::cout << "after: " << x[0] << " " << x[1] << std::endl;
return 0;
}