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

set a bit with inline asm without btsl instruction

我想在位置 p 设置一个位,而不使用带有内联 asm gcc c 代码的 btsl 指令。使用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 , %%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 [=10=]x1, %[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 [=10=]x1, %[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 [=10=]x1, %[tempreg]\n\t"
         "shl %[shift], %[tempreg]\n\t"
         "xor %[tempreg], %[val]"
    : [val]"+r"(value),
      [tempreg]"=&r"(tmp)
    : [shift]"cN"(shift));

    return value;
}