Hello,

I had a look at the debian bug #225313. This bug only raise raise when
optimization is used. I've submitted a patch, but would like to
understand if gcc behaviour was normal.


I've selected a sample of code that should raise the same issue:

=======================================================================
typedef unsigned long word;
typedef unsigned long long dword;

#define LOW_WORD(x) (word)(x)
#define HIGH_WORD(x) (*(((word *)&(x))+1))

word test(word *A)
{
  dword p, u;

  p = (dword) A[1];
  u = (dword) A[0] - LOW_WORD(p);
  A[1] = LOW_WORD(u);
  u = (dword) HIGH_WORD(u);

  return LOW_WORD(u);
}

int main(int agrc, char **argv)
{
  word t[3] = {0,0xFFFFFFFF,0};

  return test(t);
}
=======================================================================

Here are the executions of this program with and without optimization:
sh~ gcc -g -O2 -o test test.c
sh~ ./test; echo $?
0
sh~ gcc -g -O0 -o test test.c
sh~ ./test; echo $?
255



And here is the assembler code produced by -O2:
=======================================================================
08048340 <test>:
#define LOW_WORD(x) (word)(x)
#define HIGH_WORD(x) (*(((word *)&(x))+1))

word test(word *A)
{
 8048340:       55                      push   %ebp
 8048341:       89 e5                   mov    %esp,%ebp
 8048343:       83 ec 10                sub    $0x10,%esp
 8048346:       89 75 fc                mov    %esi,0xfffffffc(%ebp)
 8048349:       8b 75 08                mov    0x8(%ebp),%esi
 804834c:       89 5d f8                mov    %ebx,0xfffffff8(%ebp)
  dword p, u;

  p = (dword) A[1];
  u = (dword) A[0] - LOW_WORD(p);
  A[1] = LOW_WORD(u);
  u = (dword) HIGH_WORD(u);
 804834f:       c7 45 f4 00 00 00 00    movl   $0x0,0xfffffff4(%ebp)
 8048356:       8b 4e 04                mov    0x4(%esi),%ecx
 8048359:       8b 06                   mov    (%esi),%eax
 804835b:       29 c8                   sub    %ecx,%eax
 804835d:       89 45 f0                mov    %eax,0xfffffff0(%ebp)
 8048360:       8b 45 f0                mov    0xfffffff0(%ebp),%eax
 8048363:       89 46 04                mov    %eax,0x4(%esi)
 8048366:       8b 45 f4                mov    0xfffffff4(%ebp),%eax

  return LOW_WORD(u);
}
 8048369:       8b 5d f8                mov    0xfffffff8(%ebp),%ebx
 804836c:       8b 75 fc                mov    0xfffffffc(%ebp),%esi
 804836f:       89 45 f0                mov    %eax,0xfffffff0(%ebp)
 8048372:       8b 45 f0                mov    0xfffffff0(%ebp),%eax
 8048375:       89 ec                   mov    %ebp,%esp
 8048377:       5d                      pop    %ebp
 8048378:       c3                      ret    
 8048379:       8d b4 26 00 00 00 00    lea    0x0(%esi,1),%esi
=======================================================================

It seems to me that after 'sub    %ecx,%eax', the carry is not borrowed
(there is no sbb for the high word of u).

Is this the normal behaviour? Am I missing something? Is the C code
above implicated?

gcc warn about:
    test.c: In function `test':
    test.c:14: warning: dereferencing type-punned pointer will break
    strict-aliasing rules
Is it related?


BTW: I've fixed this by using unions (that permit access to the low and
high words) instead of dwords.
Is there a better solution?


I attach the source code.

TIA,
-- 
Nekral
typedef unsigned long word;
typedef unsigned long long dword;

#define LOW_WORD(x) (word)(x)
#define HIGH_WORD(x) (*(((word *)&(x))+1))

word test(word *A)
{
  dword p, u=0;

  p = (dword) A[1];
  u = (dword) A[0] - LOW_WORD(p);
  A[1] = LOW_WORD(u);
  u = (dword) HIGH_WORD(u);

  return LOW_WORD(u);
}

int main(int agrc, char **argv)
{
  word t[3] = {0,0xFFFFFFFF,0};

  return test(t);
}

Reply via email to