idiv ecx
mov edx, DWORD PTR _x$[esp+28]
lea eax, DWORD PTR [eax+edx*2]
In this code sequence each value is first loaded into a register before it is
used, but the values are only used in the context of this sample—the contents
of EDXand ECXare discarded after this code sequence (EAX is used for pass-
ing the result to the caller).
If you directly decompile the preceding sequence into a sequence of assign-
ment expressions, you come up with the following output:
Variable1 = Param3;
Variable2 = Variable1 + 4;
Variable1 = Param2;
Variable1 = Variable1 / Variable2
Variable3 = Param1;
Variable1 = Variable1 + Variable3 * 2;
Even though this is perfectly legal C code, it is quite different from anything
that a real programmer would ever write. In this sample, a local variable was
assigned to each register being used, which is totally unnecessary considering
that the only reason that the compiler used registers is that many instructions
simply can’t work directly with memory operands. Thus it makes sense to
track the flow of data in this sequence and eliminate all temporary register
usage. For example, you would replace the first two lines of the preceding
sequence with:
Variable2 = Param3 + 4;
So, instead of first loading the value of Param3to a local variable before
using it, you just use it directly. If you look at the following two lines, the same
principle can be applied just as easily. There is really no need for storing either
Param2nor the result of Param3 + 4, you can just compute that inside the
division expression, like this:
Variable1 = Param2 / (Param3 + 4);
The same goes for the last two lines: You simply carry over the expres-
sion from above and propagate it. This gives you the following complex
expression:
Variable1 = Param2 / (Param3 + 4) + Param1 * 2;
The preceding code is obviously far more human-readable. The elimination of
temporary storage registers is obviously a critical step in the decompilation
process. Of course, this process should not be overdone. In many cases, registers
Decompilation 469