C 在不带btsl指令的情况下使用内联asm设置位
我想在p位置设置一个位,而不使用btsl指令和内联asm gcc c代码。使用btsl指令很简单:C 在不带btsl指令的情况下使用内联asm设置位,c,assembly,gcc,x86,inline-assembly,C,Assembly,Gcc,X86,Inline Assembly,我想在p位置设置一个位,而不使用btsl指令和内联asm gcc c代码。使用btsl指令很简单: int n,p; scanf("%d%d",&n,&p); asm("btsl %1, %0" :"=m"(n) :"Ir"(p) :"cc"); 我知道设置位可以做到: n|=1<<p; 在我看来,shl指令不起作用。例如,n=20=10100。当我尝试设置第一位p
int n,p;
scanf("%d%d",&n,&p);
asm("btsl %1, %0"
:"=m"(n)
:"Ir"(p)
:"cc");
我知道设置位可以做到:
n|=1<<p;
在我看来,shl指令不起作用。例如,n=20=10100。当我尝试设置第一位p=1时,结果是22=10110,而不是21=10101。下面是Michael的示例,我已经完成了清除和切换以及设置:
unsigned long bitset(unsigned long value, uint8_t shift)
{
unsigned long tmp;
asm ("mov $0x1, %[tempreg]\n\t"
"shl %[shift], %[tempreg]\n\t"
"or %[tempreg], %[val]"
: [val]"+r"(value),
[tempreg]"=&r"(tmp)
: [shift]"cN"(shift));
return value;
}
unsigned long bitclear(unsigned long value, uint8_t shift)
{
unsigned long tmp;
asm ("mov $0x1, %[tempreg]\n\t"
"shl %[shift], %[tempreg]\n\t"
"not %[tempreg]\n\t"
"and %[tempreg], %[val]\n\t"
: [val]"+r"(value),
[tempreg]"=&r"(tmp)
: [shift]"cN"(shift));
return value;
}
unsigned long toggle(unsigned long value, uint8_t shift)
{
unsigned long tmp;
asm ("mov $0x1, %[tempreg]\n\t"
"shl %[shift], %[tempreg]\n\t"
"xor %[tempreg], %[val]"
: [val]"+r"(value),
[tempreg]"=&r"(tmp)
: [shift]"cN"(shift));
return value;
}
另外,shl$1、%%ebx并没有做您认为它能做的事情。它通过
1
移动ebx
,而不是通过ebx
移动1
。注意:不要在内联asm中使用mov
,而只使用适当的约束。您已经为p
指定了b
作为输入,因此编译器已经将其放入ebx
。所以movl%2,%%ebx
只是扩展到一个无意义的movl%ebx,%ebx
。与n
相同。您忘记将%eax
也指定为输出/关闭器。请注意,您将eax
指定为输入寄存器,但随后继续覆盖它。这是不允许的。如果将其指定为输出(或clobber,但如果它已经是输入,则不支持此操作),则可以覆盖它。您的代码实际上应该只包含shl
和或,并对输入和输出使用约束。除了shl
之外,为什么在每条指令上都使用冗余的l
操作数大小后缀?不管怎么说,没什么关系,我觉得用内联asm做这件事没有任何意义。只需编译x |=1 btsl有什么问题?如果你的CPU坏了,你应该更换CPU。你为什么要用EBX呢?那是毫无意义的。以mov
指令开始和结束也是毫无意义的,只需告诉编译器您将内容放在正确的寄存器中,并要求它以正确的寄存器开始(即ECX中的计数)。而且,这是一个错误:您编写ECX时没有声明一个clobber。(对该错误投了反对票;内联asm很难正确使用,不会出现使用错误的危险示例。如果您将其简化为“必需”的3条指令,或者如果您只是使其安全但仍然是低效的垃圾,我很乐意将其删除。)如果您真的打算使用这3条指令(mov/shl/or)然后你可以这样做:bitclear仍然只需要3条指令;你可以旋转0xFFFFFFFE
把零放在你想要的地方。@Peter Cordes,你能写下这个例子吗?我从来没有见过这样的方法来清除。
unsigned long bitset(unsigned long value, uint8_t shift)
{
unsigned long tmp;
asm ("mov $0x1, %[tempreg]\n\t"
"shl %[shift], %[tempreg]\n\t"
"or %[tempreg], %[val]"
: [val]"+r"(value),
[tempreg]"=&r"(tmp)
: [shift]"cN"(shift));
return value;
}
unsigned long bitclear(unsigned long value, uint8_t shift)
{
unsigned long tmp;
asm ("mov $0x1, %[tempreg]\n\t"
"shl %[shift], %[tempreg]\n\t"
"not %[tempreg]\n\t"
"and %[tempreg], %[val]\n\t"
: [val]"+r"(value),
[tempreg]"=&r"(tmp)
: [shift]"cN"(shift));
return value;
}
unsigned long toggle(unsigned long value, uint8_t shift)
{
unsigned long tmp;
asm ("mov $0x1, %[tempreg]\n\t"
"shl %[shift], %[tempreg]\n\t"
"xor %[tempreg], %[val]"
: [val]"+r"(value),
[tempreg]"=&r"(tmp)
: [shift]"cN"(shift));
return value;
}