在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;
}