在没有btsl指令的情况下使用内联asm进行设置

问题描述

我想在不使用btsl指令和内联asm gcc c代码的情况下将位置p设置为一点。使用btsl指令很简单:

int n,p;
scanf("%d%d",&n,&p);
asm("btsl %1,%0"
:"=m"(n)
:"Ir"(p)
:"cc");

我知道通过设置位可以做到:

n|=1<<p;

现在,我正在使用嵌入式asm:

  asm("movl %1,%%eax;"
      "movl %2,%%ebx;" 
      "shl $1,%%ebx;"
      "orl %%ebx,%%eax;"
      "movl %%eax,%0;"
      
  :"=b"(n)
  :"a"(n),"b"(p)
  :"cc");
  printf("%d\n",n);

在我看来,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,%[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,%[tempreg]\n\t"
         "xor %[tempreg],[tempreg]"=&r"(tmp)
    : [shift]"cN"(shift));

    return value;
}