Search code examples
cassemblygccx86inline-assembly

set a bit with inline asm without btsl instruction


I want to set a bit at position p without using btsl instruction with inline asm gcc c code. Using btsl instruction is simple:

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

I know for setting bit it can be done:

n|=1<<p;

Now, I'm doing so with inline 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);

It seems to me shl instruction doesn't work. For instance n=20=10100. When I try to set the first bit p=1 the result is 22=10110 instead of 21=10101


Solution

  • Folowing Michael's example, I've done clear and toggle as well as set:

    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;
    }