我很难理解某些特定的影响 GCC中用于内联汇编的约束。
在下面的示例中,如果我在输出上运行“ = X”,在所有输入上运行“ X”,则这2条打印输出
0x562f39629260,100
0x14,100
这表示指向我分配的缓冲区的指针已更改。导致段错误是尝试读取缓冲区的内容 在我的汇编代码之后。
相反,如果我在输出上输入“ + X”或在输入上输入“ m”, 地址保持不变,打印输出:
0x55571bb83260,100
0x55571bb83260,100
而且我可以安全地读取我的缓冲区而无需进行段错误。
我不知道如何/为什么应该/应该修改此指针? 有没有办法安全地选择约束? GCC在线文档 对此没有太多见识。
非常感谢
int main() {
long size = 100;
char * buffer = (char*)malloc(size*sizeof(char));
printf("%p, %d\n",buffer, size);
__asm__(
"mov %[out], %%rcx \n"
"mov %[size], %%rbx \n"
"loop: \n"
"movb $1, (%%rcx) \n"
"add $1, %%rcx \n"
"sub $1, %%rbx \n"
"jnz loop \n"
: "=X"(buffer) //outputs
: [out]"X"(buffer), [size]"X"(size) //inputs
: "rbx", "rcx" //clobbers
);
printf("%p, %d\n",buffer, size);
return 0;
}
答案 0 :(得分:2)
=
中的=X
表示这是仅输出约束(与+
的更新约束相反)。这意味着期望汇编代码向操作数(到%0
)中写入一些内容,并且这将是输出的值。但是由于您的汇编代码从未写入%0
,因此您会在该位置(可能是寄存器分配器选择的寄存器)碰到任何垃圾。
尝试在asm代码中添加mov %%rcx,%0
行,以查看实际发生的情况。
最可能您真正想要的是类似的东西:
__asm__ volatile (
"mov %[size], %%rbx \n"
"loop: \n"
"movb $1, (%[out]) \n"
"add $1, %[out] \n"
"sub $1, %%rbx \n"
"jnz loop \n"
: [out]"+r"(buffer) //outputs
: [size]"X"(size) //inputs
: "rbx", "memory" //clobbers
);
请注意,这使buffer
指向插入值的后面(在缓冲区的末尾)-不清楚是否是您想要的。您可以对大小做同样的事情,使其更简单:
__asm__ volatile (
"loop: \n"
"movb $1, (%[out]) \n"
"add $1, %[out] \n"
"sub $1, %[size] \n"
"jnz loop \n"
: [out]"+r"(buffer), [size]"+X"(size) //outputs
: //inputs
: "memory" //clobbers
);
虽然根本不使用asm会更简单(对于优化程序来说更好):
do { *buffer++ = '\1'; } while (--size);
因此,总结下面的所有评论,您可能想要的是:
long size = 100;
char buffer[100];
char *temp;
__asm__(
"loop: \n"
"movb $1, (%[out]) \n"
"add $1, %[out] \n"
"sub $1, %[size] \n"
"jnz loop \n"
: [out]"=r"(temp), [size]"+X"(size), "=m"(buffer) //outputs
: "0"(buffer) // inputs
) // no clobbers
"=m"
约束,而不是使用内存阻塞和易失性,意味着如果不使用任何结果,则可以消除死代码"=m"(*(char (*)[100])buffer)
可用于获取整个缓冲区的约束。但是,我支持我先前的评论,即不使用asm编写脚本会更好。它更容易理解,并且编译器的优化器可能会为您向量化它。