very ambigous code, and i am not sure it runs the same way for all compilers...
first, you have six %d but you put just 4 extra args, this means that last two %d will give you random rubbish.
the output of my gcc says:
4 5 5 5 (rubbish)
if we think the args are evaluated from left to right, we have:
first arg: i++, i is 5, so first %d should be 5 (it is not!), then i becomes 6; next one should give 6 in output (since there's a post decrement) and then i becomes 5 again...
but as i've said, the first is not 4...
then, thinking about stack order, the last is the first evaluated? then the last %d should give 4... and this is false too...
so... let me take a look at the code,
[....
part that is not interesting... prepare the stack, local vars and so on...]
mov DWORD PTR [%ebp-8], 5
this one initialize what for us is the "int i" to 5
sub DWORD PTR [%ebp-8], 1
what's up... it executes a "--i" first...
add DWORD PTR [%ebp-8], 1
then it execute a "++i" !! nothing happened! still i==5!
mov %edx, DWORD PTR [%ebp-8]
now save the i value into edx reg, at this time i is 5 (so edx==5)
sub DWORD PTR [%ebp-8], 1
execute a "i--", now i==4
mov %ecx, DWORD PTR [%ebp-8]
save i into ecx regs (i.e. ecx==4)
add DWORD PTR [%ebp-8], 1
execute a "i++", now i==5 again
mov DWORD PTR [%esp+24], 0
mov DWORD PTR [%esp+20], 0
this is a fix i added (my printf was with two extra arg); it put these last two args on the prepared stack
mov %eax, DWORD PTR [%ebp-8]
get i into eax... (remember now is 5)
mov DWORD PTR [%esp+16], %eax
put it on the stack (this is the fourth argument, look at +16)
mov %eax, DWORD PTR [%ebp-8]
mov DWORD PTR [%esp+12], %eax
again the same value (and redundant code) into third position on the stack for arguments.
mov DWORD PTR [%esp+8], %edx
now it gets the saved value: edx==5 as second argument
mov DWORD PTR [%esp+4], %ecx
and ecx was 4 as first argument...
mov DWORD PTR [%esp], OFFSET FLAT:.LC0
put the template as first argumenti
call printf
print it....
[... final stuffs ...]
now let us interpret what's going on: simply this teach us (and we should have known before!?) that arguments are taken from right to left and pre-increment/decrement are executed before any evaluation of the "printf(...)"; so first --i is executed... the ++i is executed... this makes the "i" keep the value of 5.
the pre-inc/dec are executed before "real" evaluation of the statement (so to say), ... so at then end of the game instead of third and fourth argument we have simply the value of "i", that is still 5 after the evaluation of i++ and i--.
in fact the next step is the evaluation of i-- (second arg); since this is a post-dec, first the value of i (5) is taken. after this i is 4.
then the first extra arg is evaluated; this is a post-inc, so first the value of i (4) is taken... ater this i is again 5. and this is the value we shall have for the third and fourth.
maybe i have made it harder than it is... hope you get something interesting from this.
first, you have six %d but you put just 4 extra args, this means that last two %d will give you random rubbish.
the output of my gcc says:
4 5 5 5 (rubbish)
if we think the args are evaluated from left to right, we have:
first arg: i++, i is 5, so first %d should be 5 (it is not!), then i becomes 6; next one should give 6 in output (since there's a post decrement) and then i becomes 5 again...
but as i've said, the first is not 4...
then, thinking about stack order, the last is the first evaluated? then the last %d should give 4... and this is false too...
so... let me take a look at the code,
[....
part that is not interesting... prepare the stack, local vars and so on...]
mov DWORD PTR [%ebp-8], 5
this one initialize what for us is the "int i" to 5
sub DWORD PTR [%ebp-8], 1
what's up... it executes a "--i" first...
add DWORD PTR [%ebp-8], 1
then it execute a "++i" !! nothing happened! still i==5!
mov %edx, DWORD PTR [%ebp-8]
now save the i value into edx reg, at this time i is 5 (so edx==5)
sub DWORD PTR [%ebp-8], 1
execute a "i--", now i==4
mov %ecx, DWORD PTR [%ebp-8]
save i into ecx regs (i.e. ecx==4)
add DWORD PTR [%ebp-8], 1
execute a "i++", now i==5 again
mov DWORD PTR [%esp+24], 0
mov DWORD PTR [%esp+20], 0
this is a fix i added (my printf was with two extra arg); it put these last two args on the prepared stack
mov %eax, DWORD PTR [%ebp-8]
get i into eax... (remember now is 5)
mov DWORD PTR [%esp+16], %eax
put it on the stack (this is the fourth argument, look at +16)
mov %eax, DWORD PTR [%ebp-8]
mov DWORD PTR [%esp+12], %eax
again the same value (and redundant code) into third position on the stack for arguments.
mov DWORD PTR [%esp+8], %edx
now it gets the saved value: edx==5 as second argument
mov DWORD PTR [%esp+4], %ecx
and ecx was 4 as first argument...
mov DWORD PTR [%esp], OFFSET FLAT:.LC0
put the template as first argumenti
call printf
print it....
[... final stuffs ...]
now let us interpret what's going on: simply this teach us (and we should have known before!?) that arguments are taken from right to left and pre-increment/decrement are executed before any evaluation of the "printf(...)"; so first --i is executed... the ++i is executed... this makes the "i" keep the value of 5.
the pre-inc/dec are executed before "real" evaluation of the statement (so to say), ... so at then end of the game instead of third and fourth argument we have simply the value of "i", that is still 5 after the evaluation of i++ and i--.
in fact the next step is the evaluation of i-- (second arg); since this is a post-dec, first the value of i (5) is taken. after this i is 4.
then the first extra arg is evaluated; this is a post-inc, so first the value of i (4) is taken... ater this i is again 5. and this is the value we shall have for the third and fourth.
maybe i have made it harder than it is... hope you get something interesting from this.
No comments:
Post a Comment