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