Wednesday, April 12, 2017

Understanding post increments

Understanding post increments Did you happen to use a post increment on a assignment resulting in strange behavior?

What the values of p and q would be?

the problem

You may be tempted to say 99... but let see what a run tell us:

first run

Surprised? I was...

The following analysis was made on a x64 Arch Linux box.

What is going on?

Unfortunately, the answer to this question is not short or easy. But I will try to make a short one.


Short answer
The trick is about how x86 operations occur on temporal values. printf is called with p and q containing 98. When the process gets back from the call to printf, it ends and the increment never happens.

Too vague answer for a blog called Wonderful Coding? Read the long one!

Long answer
To understand what is going on we need to look at the assembly code. The C code is too high-level and it does not show us what is really going on, what our CPU is doing.

First of all, having the binary with debug information will be really helpful. Without this, we would need to read plain asm and mentally map the set of instructions to our C code. Something a little annoying. So, let's build our program with debug information:

compiling debug

Now we disassemble the binary using objdump with the following parameters:
-j .text - To instruct objdump to only disassemble the text section.
-S - To mix the asm code with our C code. Here is why we built debug.
-M intel - This is optional, but I prefer to read Intel style asm.

disasseble

Let's focus on the interesting part of the output

asm .text

I will point to the important part and explain what is going on.

p=98

mov copies a 32 bits integer (DWORD) with the 98 hexa representation (0x62) to a position rbp-0x4 (p) in the stack.

q=p++

rpb-0x4 (AKA p) is copied to EAX.
EAX is a sub-register of RAX, so the second line instructs the CPU to do 98+1 and copy it to EDX.
Then EDX (99) es copied to rbp-0x4 (p). Here p contains 99.
Then EAX, containing 98, is copied to rbp-0x8 (AKA q). Remember, the stack grows downward.

At this point p contains 99 and q contains 98.

p=98_2

As in 4004fe address, 98 (0x62) is assigned to p (rbp-0x4).

p=p++

These opcodes are almost the same than those at 400505, except for the last one.
The first line copies rbp-0x4 (p) to EAX.
The second line tell the CPU to do 98+1 and copy it to EDX.
The third line copies EDX (99) to rbp-0x4 (p).
The fourth line copies EAX (98) to rbp-0x4 (p).

At this point both p and q contain 98, and printf is called.

printf

By the end of the function, 0 is assigned to EAX, meaning that the function returned successfully.

return

Here 0 is assigned to EAX and the program ends.

Conclusion

p = p++ returns p. The stored value resets the value of p to 98. The increment is performed in a temporary location that is never called.

No comments:

Post a Comment