static inline void *__memset(void *s, char c, size_t n) {
int d0, d1;
asm volatile (
"rep; stosb;"
: "=&c" (d0), "=&D" (d1)
: "0" (n), "a" (c), "1" (s)
: "memory");
return s;
}"d0“和"d1”是用来做什么的?你能完整地解释一下所有的代码吗?谢谢!
发布于 2012-03-20 23:58:39
"d0“和"d1”是用来做什么的?
实际上,它表示%ecx和%edi (假设32位)的最终值分别存储在d0和d1中。这有几个目的:
它让编译器知道,作为输出,这些寄存器被有效地销毁了。通过将它们分配给临时变量,优化编译器还知道不需要实际执行“存储”操作。
"=&“将这些指定为早期截断操作数。它们可能会在所有输入被使用之前被写入。因此,如果编译器可以自由选择输入寄存器,它就不应该将这两个寄存器别名。
对于%ecx来说,这在技术上不是必需的,因为它被显式地命名为输入:"0" (n) -本例中的“rep”计数。我也不确定这对于%edi是不是必要的,因为在使用输入"1" (s)和执行指令之前,它不能被更新。同样,由于它被显式命名为输入,编译器不能自由选择另一个寄存器。简而言之,"=&“在这里不会有任何影响,但它不会做任何事情。
由于"a" (c)指定了一个设置为(c)的仅用于输入的寄存器%eax,编译器可能会认为%eax在'asm‘之后仍然保留这个值-- "rep; stosb;"确实就是这种情况。
"memory"指定可以以编译器不知道的方式修改内存-在本例中,编译器将从(r)开始的(n)字节设置为值(c) -假设方向标志被清除,它应该清除方向标志。这确实具有强制重新加载值的效果,因为编译器不能再假设寄存器反映它们应该反映的内存值。这不会有什么坏处,而且对于一般情况下的memset来说,可能有必要保证它的安全性,但它通常是过度杀伤力。
编辑:输入操作数不能与压缩操作数重叠。将某些内容指定为仅限输入的和 clobbered是没有意义的。我认为编译器不允许这样做,即使这样,使用模棱两可的规范也不是明智之举。从手册中:
您不能以与输入或输出操作数重叠的方式编写clobber描述。例如,如果您在clobber列表中提到寄存器,则可能没有一个操作数描述具有一个成员的寄存器类。
回顾一些旧的答案,我想我应该添加一个链接,指向优秀的 GCC内联ASM教程。这篇文章建立在前几节的基础上,不像gcc手册,它最好被描述为“参考”,并不真正适合任何类型的结构化学习。
发布于 2012-03-20 21:53:22
您需要了解一下gcc扩展的内联asm格式:
输出
"=&c"将d0与ecx寄存器关联,并将其标记为只写。对于edi寄存器,&意味着可以在edi结束之前对其进行修改
输入
"0" (n)将n与前面提到的寄存器关联。在您的示例中,使用ecx"a" (c)关联c与eax"1" (s)关联s与edi。
组件
现在你就知道了。重复此ecx (n次):将eax (c)存储到edi中,然后递增它。
那么,为什么会有未使用的d0和d1呢?我没有把握。我也认为它们在这种情况下没有用,整个输出部分可以留空,但我认为在输入约束中指定"writable“和"early-clobbered”是不可能的。所以我认为d0和d1是为了让&成为可能。
我会试着这样写:
asm volatile (
"rep\n"
"stosb\n"
:
: "c" (n), "a" (c), "D" (s)
: "%ecx", "%edi", "memory"
);https://stackoverflow.com/questions/9787861
复制相似问题