This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
An ia32 LOCK/XADD bug.
- To: GNU C Library <libc-alpha at sourceware dot cygnus dot com>
- Subject: An ia32 LOCK/XADD bug.
- From: "H . J . Lu" <hjl at lucon dot org>
- Date: Thu, 17 May 2001 00:15:56 -0700
- Cc: binutils at sourceware dot cygnus dot com
- References: <20010516125536.A6006@lucon.org>
On Wed, May 16, 2001 at 12:55:36PM -0700, H . J . Lu wrote:
> Has anyone run LD_PROFILE lately? I got
>
> # LD_PROFILE=libc.so.6 ls
> zsh: 4096 illegal hardware instruction LD_PROFILE=libc.so.6 ls
>
> I will track it down.
>
>
It turned out it might be a bug in glibc:
# gcc a.c
# gdb a.out
(gdb) r
3
4, 3
4
Program received signal SIGILL, Illegal instruction.
exchange_and_add_2 (mem=0x80496e8, val=2) at a.c:23
23 __asm__ __volatile__ ("lock; xaddl %0,%2"
(gdb) disass exchange_and_add_2
Dump of assembler code for function exchange_and_add_2:
0x8048554 <exchange_and_add_2>: push %ebp
0x8048555 <exchange_and_add_2+1>: mov %esp,%ebp
0x8048557 <exchange_and_add_2+3>: mov 0x8(%ebp),%eax
0x804855a <exchange_and_add_2+6>: mov 0xc(%ebp),%edx
0x804855d <exchange_and_add_2+9>: lock xadd %edx,%edx
0x8048561 <exchange_and_add_2+13>: mov %edx,%eax
0x8048563 <exchange_and_add_2+15>: pop %ebp
0x8048564 <exchange_and_add_2+16>: ret
End of assembler dump.
It looks like
lock xadd %edx,%edx
is an illegal instruction on ia32. I cannot find anything in Intel
reference manual to say you cannot have LOCK on insn where DST/SRC are
reg or same. My questions are
1. How to write a correct exchange_and_add? Is exchange_and_add_1 ok?
2. If "lock xadd %edx,%edx" is really an illegal instruction on ia32,
how should we fix gas to detect that?
H.J.
---
#include <stdio.h>
#include <inttypes.h>
static volatile uint32_t fromidx;
static inline uint32_t
__attribute__ ((unused))
exchange_and_add_1 (volatile uint32_t *mem, uint32_t val)
{
register uint32_t result;
__asm__ __volatile__ ("lock; xaddl %0,%1"
: "=r" (result), "=m" (*mem)
: "0" (val), "1" (*mem));
return result;
}
static inline uint32_t
__attribute__ ((unused))
exchange_and_add_2 (volatile uint32_t *mem, uint32_t val)
{
register uint32_t result;
__asm__ __volatile__ ("lock; xaddl %0,%2"
: "=r" (result), "=m" (*mem)
: "0" (val), "1" (*mem));
return result;
}
int
main ()
{
uint32_t newfromidx;
fromidx = 3;
printf ("%d\n", fromidx);
newfromidx = exchange_and_add_1 (&fromidx, 1);
printf ("%d, %d\n", fromidx, newfromidx);
fromidx = 4;
printf ("%d\n", fromidx);
newfromidx = exchange_and_add_2 (&fromidx, 2);
printf ("%d, %d\n", fromidx, newfromidx);
return 0;
}