I am a beginner on CS and am using CSAPP to learn some knowledge.
(code below were built in 32-bit)
When I was writing my bits.c
of CSAPP Lab datalab, I wrote a WRONG implementation in isLessOrEqual
like this. It's a learning lab and the checker compiler limited available operators to ! ~ & ^ | + << >>
.
int isLessOrEqual(int x, int y) {
int a = y + (~x + 1);
return !(a >> 31);
}
I know it's wrong because when x=0x80000000(TMIN) and y=0x7fffffff(TMAX), it will return 0.
But it was passed from btest
(result = 1), when I inserted some printf
to output some logs I got a strange result.
if (x == 0x80000000 && y == 0x7fffffff) {
printf("x = 0x%08x, y = 0x%08x, a = 0x%08x, a >> 31 = 0x%08x, a >> 31 & 1 = %d, result = %d, result & 1 = %d\n", x, y, a, a >> 31, a >> 31 & 1, !(a >> 31), !(a >> 31 & 1));
if (a >> 31 == 0xffffffff)
printf("a >> 31 = 0xffffffff, but !(a >> 31) = %d, and !!(a >> 31) = %d, !0xffffffff = %d\n", !(a >> 31), !!(a >> 31), !0xffffffff);
}
Result from the log code.
x = 0x80000000, y = 0x7fffffff, a = 0xffffffff, a >> 31 = 0xffffffff, a >> 31 & 1 = 1, result = 1, result & 1 = 1
a >> 31 = 0xffffffff, but !(a >> 31) = 1, and !!(a >> 31) = 1, !0xffffffff = 0
I know a >> 31 = 0xffffffff
and !0xffffffff = 0
are true because they fit my calculations.
But why did I get !(a >> 31) = 1
and !!(a >> 31) = 1
, could anyone explain that please?
I copied all code to a new file and compiled it, it returned right 0.
UPDATE:
My friend analyzed the program with IDA and found the compiler optimized my code to that below directly.
_BOOL4 __cdecl isLessOrEqual(int a1, int a2)
{
if ( a1 == 0x80000000 && a2 == 0x7FFFFFFF )
{
printf(
"x = 0x%08x, y = 0x%08x, a = 0x%08x, a >> 31 = 0x%08x, a >> 31 & 1 = %d, result = %d, result & 1 = %d\n",
0x80000000,
0x7FFFFFFF,
-1,
-1,
1,
1,
1);
printf("a >> 31 = 0xffffffff, but !(a >> 31) = %d, and !!(a >> 31) = %d, !0xffffffff = %d\n", 1, 1, 0);
}
return a2 >= a1;
}
And I tested it with new file and compiled it with different flags.
#include <stdio.h>
int isLessOrEqual(int x, int y) {
int a = y + (~x + 1);
int result = !(a >> 31);
if (x == 0x80000000 && y == 0x7fffffff) {
printf("x = 0x%08x, y = 0x%08x, a = 0x%08x, a >> 31 = 0x%08x, a >> 31 & 1 = %d, result = %d, result & 1 = %d\n", x, y, a, a >> 31, a >> 31 & 1, !(a >> 31), !(a >> 31 & 1));
if (a >> 31 == 0xffffffff)
printf("a >> 31 = 0xffffffff, but !(a >> 31) = %d, and !!(a >> 31) = %d, !0xffffffff = %d\n", !(a >> 31), !!(a >> 31), !0xffffffff);
}
return result;
}
int main() {
printf("%d\n", isLessOrEqual(0x80000000, 0x7fffffff));
}
Shell result:
***:~/workspace/$ gcc -o hello -m32 -O hello.c
***:~/workspace/$ ./hello
x = 0x80000000, y = 0x7fffffff, a = 0xffffffff, a >> 31 = 0xffffffff, a >> 31 & 1 = 1, result = 1, result & 1 = 1
a >> 31 = 0xffffffff, but !(a >> 31) = 1, and !!(a >> 31) = 1, !0xffffffff = 0
1
***:~/workspace/$ gcc -o hello -m32 hello.c
***:~/workspace/$ ./hello
x = 0x80000000, y = 0x7fffffff, a = 0xffffffff, a >> 31 = 0xffffffff, a >> 31 & 1 = 1, result = 0, result & 1 = 0
a >> 31 = 0xffffffff, but !(a >> 31) = 0, and !!(a >> 31) = 1, !0xffffffff = 0
0