Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Illegal instruction in ASM: lock cmpxchg dest, src

Tags:

x86

assembly

I've been messing around with some x86 assembly as its come up in a number of my classes. In particular, I've wanted to expose compare-and-swap (CAS) as a user function. This is with the intent that I can implement my own locks.

I'm using Linux 2.6.31 with GCC 4.1.1 on an Intel CPU.

I have the following:

// int cmpxchg(int *dest, int expected, int update)
.globl cmpxchg
cmpxchg:
  pushl %ebp
  movl  %esp, %ebp

  // edx holds dest
  movl 8(%ebp), %edx
  // eax holds expected value
  movl 12(%ebp), %eax
  // ecx holds the new value
  movl 16(%ebp), %ecx

  // cmpxchg dest_addr, exp_value
  // compare to %eax is implicit
  lock cmpxchgl %edx, %ecx

  leave
  ret

This is within a *.s file, which I compile with my driver program. When I include the line

  lock cmpxchgl %edx, %ecx

and execute, I receive an "Illegal instruction" error. When I replace the line with

  cmpxchgl %edx, %ecx

my code seems to run fine.

First off, is lock necessary? I'm not sure whether cmpxchgl is naturally atomic, so I used lock to be sure. As a userland program, am I even allowed to use lock?

Thanks

================================================================

My final code (for those who may wander here in the future):

// int cmpxchg(int *dest, int expected, int update)
.globl cmpxchg
cmpxchg:
  pushl %ebp
  movl  %esp, %ebp

  // edx holds dest, use eDx for Destination ;-)
  movl 8(%ebp), %edx
  // eax holds expected value implicitly
  movl 12(%ebp), %eax

  // cmpxchg dest_add, src_value
  lock cmpxchgl %edx, 16(%ebp)

  leave
  ret
like image 796
Willi Ballenthin Avatar asked Dec 13 '22 01:12

Willi Ballenthin


1 Answers

You need cmpxchgl %edx, (%ecx)

This operation doesn't make sense unless the destination is a memory operand, however the instruction allows a register destination. The CPU will fault if the instruction uses a register mode.

I tried it, your code works with a memory operand. I don't know if you realize this, but this sequence (with a register destination) has a popular name: "the f00fc7c8 bug" or "the F00F bug". In the Pentium days this was an "HCF" (halt and catch fire) or "killer poke" instruction, as it would generate an exception which it would not then be able to service because the bus was locked, and it was callable from user mode. I think there may have been an OS-level software workaround.

like image 83
DigitalRoss Avatar answered Jan 18 '23 04:01

DigitalRoss