我想使用GCC扩展内联ASM编写以下循环:
long* arr = new long[ARR_LEN]();
long* act_ptr = arr;
long* end_ptr = arr + ARR_LEN;
while (act_ptr < end_ptr)
{
*act_ptr = SOME_VALUE;
act_ptr += STEP_SIZE;
}
delete[] arr;
分配长度为long
的{{1}}类型的数组并进行零初始化。循环遍历数组,增量为{{1}}。每个被触摸的元素都设置为ARR_LEN
。
嗯,这是我在GAS的第一次尝试:
STEP_SIZE
正如评论中所提到的,这个汇编代码确实更像是一个SOME_VALUE
循环,但事实上确实做了同样的工作。
关于这段代码的奇怪之处在于,它起初对我来说很好。但是当我后来试图让它在另一个项目中工作时,它似乎似乎没有做任何事情。我甚至制作了一些工作项目的1:1副本,再次编译并且......结果仍然是随机的。
也许我对输入操作数采取了错误的约束,但我实际上已经尝试了几乎所有这些约束,而我还没有真正的想法。令我特别困惑的是,它在某些情况下仍然有效。
我不是ASM的专家,虽然我还在大学时就学会了。请注意,我不是在寻找优化 - 我只是想了解内联汇编的工作原理。所以这是我的问题:我的尝试有什么根本性的错误,或者我在这里犯了一个更微妙的错误?提前谢谢。
(使用g ++ MinGW Win32 x86 v.4.8.1)
更新
到目前为止,我已经尝试过在此提供的所有建议。特别是我试过
long* arr = new long[ARR_LEN]();
asm volatile
(
"loop:"
"movl %[sval], (%[aptr]);"
"leal (%[aptr], %[incr], 4), %[aptr];"
"cmpl %[eptr], %[aptr];"
"jl loop;"
: // no output
: [aptr] "r" (arr),
[eptr] "r" (arr + ARR_LEN),
[incr] "r" (STEP_SIZE),
[sval] "i" (SOME_VALUE)
: "cc", "memory"
);
delete[] arr;
,结果相同,do {...} while
,仍然相同。与此同时,我非常了解官方documentation,但我仍然看不到我的错误。
答案 0 :(得分:2)
您正在修改不允许的输入操作数(aptr
)。约束它与输出操作数匹配或将其更改为输入/输出操作数。
答案 1 :(得分:2)
这是一个具有预期行为的完整代码。
%%rbx
代替%%ebx
作为数组的基址。出于同样的原因,应使用leaq
和cmpq
代替leal
和cmpl
。 movq
,因为数组的类型为long
。long
是8字节而不是4字节。 jl
应更改为jg
。 ebx
)。 无法使用约束"r"
。 "r"
表示可以使用任何寄存器,但leaq
不接受任何寄存器组合。看这里:x86 addressing modes
#include <iostream>
using namespace std;
int main(){
int ARR_LEN=20;
int STEP_SIZE=2;
long SOME_VALUE=100;
long* arr = new long[ARR_LEN];
int i;
for (i=0; i<ARR_LEN; i++){
arr[i] = 0;
}
__asm__ __volatile__
(
"loop:"
"movq %%rdx, (%%rbx);"
"leaq (%%rbx, %%rcx, 8), %%rbx;"
"cmpq %%rbx, %%rax;"
"jg loop;"
: // no output
: "b" (arr),
"a" (arr+ARR_LEN),
"c" (STEP_SIZE),
"d" (SOME_VALUE)
: "cc", "memory"
);
for (i=0; i<ARR_LEN; i++){
cout << "element " << i << " is " << arr[i] << endl;
}
delete[] arr;
return 0;
}
答案 2 :(得分:1)
一个适用于x86和x64的答案怎么样(虽然它确实假设long总是4个字节,一个Windows)? OP的主要变化是使用&#34; + r&#34;和(临时)。
#include <iostream>
using namespace std;
int main(){
int ARR_LEN=20;
size_t STEP_SIZE=2;
long SOME_VALUE=100;
long* arr = new long[ARR_LEN];
for (int i=0; i<ARR_LEN; i++){
arr[i] = 0;
}
long* temp = arr;
asm volatile (
"loop:\n\t"
"movl %[sval], (%[aptr])\n\t"
"lea (%[aptr], %[incr], %c[size]), %[aptr]\n\t"
"cmp %[eptr], %[aptr]\n\t"
"jl loop\n\t"
: [aptr] "+r" (temp)
: [eptr] "r" (arr + ARR_LEN),
[incr] "r" (STEP_SIZE),
[sval] "i" (SOME_VALUE),
[size] "i" (sizeof(long))
: "cc", "memory"
);
for (int i=0; i<ARR_LEN; i++){
cout << "element " << i << " is " << arr[i] << endl;
}
delete[] arr;
return 0;
}