- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试内联汇编的示例:http://www.delorie.com/djgpp/doc/brennan/brennan_att_inline_djgpp.html但是有些东西让我对破坏感到困惑:
"Well, it really helps when optimizing, when GCC can know exactly what you're doing with the registers before and after....It's even smart enough to know that if you tell it to put (x+1) in a register, then if you don't clobber it, and later C code refers to (x+1), and it was able to keep that register free, it will reuse the computation. Whew."
教程中关于 clobber 列表的一些不一致之处:
对于在输入/输出列表中指定的寄存器,没有必要将它们放入 GCC 知道的 clobber 列表中;然而,在有关 rep_movsl(或 rep_stosl)的示例中:
asm ("cld\n\t" “代表\n\t” “斯托斯” :/* 没有输出寄存器 */ : "c"(count), "a"(fill_value), "D"(dest) : "%ecx", "%edi");
尽管“S、D、c”在输出操作数中,但它们再次被列为已破坏。我在 C 中尝试了一个简单的片段:
#include<stdio.h>
int main()
{
int a[] = {2, 4, 6};
int b[3];
int n = 3;
int v = 12;
asm ("cld\n\t"
"rep\n\t"
"movsl"
:
: "S" (a), "D" (b), "c" (n)
: );
// : "%ecx", "%esi", "%edi" );
printf("%d\n", b[1]);
}
如果我使用注释过的 clobber 列表,GCC 会提示:
a.c:8:3: error: can't find a register in class ‘CREG’ while reloading ‘asm’ a.c:8:3: error: ‘asm’ operand has impossible constraints
如果我使用空的 clobber 列表,它会编译并输出 4。
最佳答案
您引用的文件似乎明显不准确。以下是 asm 操作数约束对 GCC 的实际意义:
此外,当前 (GCC 4.7) 手册包含以下关键段落:
You may not write a clobber description in a way that overlaps with an input or output operand. For example, you may not have an operand describing a register class with one member if you mention that register in the clobber list. Variables declared to live in specific registers (see Explicit Reg Vars), and used as asm input or output operands must have no part mentioned in the clobber description. There is no way for you to specify that an input operand is modified without also specifying it as an output operand. Note that if all the output operands you specify are for this purpose (and hence unused), you will then also need to specify volatile for the asm construct, as described below, to prevent GCC from deleting the asm statement as unused.
这就是为什么尝试输入和破坏某些寄存器对您来说失败的原因。
现在,现在插入 rep movsl 有点傻——只需使用 memcpy
并让 GCC 将其替换为适合你的最佳指令序列——但是编写示例的正确方法是
int main()
{
int a[] = {2, 4, 6};
int b[3];
int n = 3;
int v = 12;
int *ap = a, *bp = b;
asm volatile ("rep movsl" : "+S" (ap), "+D" (bp), "+c" (n) : : "memory");
printf("%d\n", b[1]);
}
您需要 ap
和 bp
中间变量,因为数组的地址不是左值,所以它不能出现在输出约束中。 “+r”符号告诉 GCC 这个寄存器既是输入又是输出。 'volatile' 是必需的,因为在 asm
之后所有输出操作数都未使用,因此 GCC 会高兴地删除它(理论上它只是因为它对输出操作数所做的事情而存在) .将“内存”放在破坏列表中就是告诉 GCC 该操作修改了内存的方式。最后,微优化:GCC 永远不会发布“std”,因此您不需要“cld”(这实际上由 x86 ABI 保证)。
我所做的大部分更改不会影响像这样的小测试程序是否正常运行;但是,它们在全尺寸程序中都是必不可少的,可以防止细微的优化错误。例如,如果您遗漏了“内存”破坏,GCC 将有权将 b[1]
的负载提升到 asm
之上!
关于rep_movsl 的 Clobber 列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13258464/
我正在尝试内联汇编的示例:http://www.delorie.com/djgpp/doc/brennan/brennan_att_inline_djgpp.html但是有些东西让我对破坏感到困惑:
我是一名优秀的程序员,十分优秀!