Possible Duplicate:
What's the point of LEA EAX, [EAX]?
During a disassembly practice, I have observed the following code:
test.cpp:
#include <stdio.h>
int main(int argc, char * argv[]) {
for (int i = 0; i < 10 ; ++i) {
printf("%i\n", i);
}
int i = 0;
while ( i < 10) {
printf("%i\n", i);
++i;
}
return 0;
}
compiling using vc++ 2008 with optimization:
cl /Ox test.cpp
disassembly of main function:
.text:00401000 var_4 = dword ptr -4 ; BTW, IDA fails to see that esi is pushed to save it, not to allocate space to local variable
.text:00401000
.text:00401000 push esi
.text:00401001 xor esi, esi
.text:00401003
.text:00401003 loc_401003: ; CODE XREF: sub_401000+15j
.text:00401003 push esi
.text:00401004 push offset byte_40A150
.text:00401009 call sub_401038 ; printf
.text:0040100E inc esi
.text:0040100F add esp, 8
.text:00401012 cmp esi, 0Ah
.text:00401015 jl short loc_401003
.text:00401017 xor esi, esi
.text:00401019 lea esp, [esp+0]
.text:00401020
.text:00401020 loc_401020: ; CODE XREF: sub_401000+32j
.text:00401020 push esi
.text:00401021 push offset unk_40A154
.text:00401026 call sub_401038 ; printf
.text:0040102B inc esi
.text:0040102C add esp, 8
.text:0040102F cmp esi, 0Ah
.text:00401032 jl short loc_401020
.text:00401034 xor eax, eax
.text:00401036 pop esi
.text:00401037 retn
Now, I am not exactly an expert, as you can see from the example code, but I was able to figure out this assembly listing, taking into account that I wrote the original code. The only thing that bothers me is the following line:
.text:00401019 lea esp, [esp+0]
Why does the compiler do that? It doesn't effect any register or flag, and it seems like a redundant code. The only thing I can think about is that the compiler aligns the code where the jmp goes to in the second loop (loc_401020) is this might be the reason?
Yes, it looks like it's inserting padding to align the jump target. If you use /Fa
to have the compiler produce assembly output, that'll show up as npad 7
, making it explicit that it's inserting padding. From there, it's up to the assembler to pick out the most efficient sequence of instructions it can find to use up the specified space while using as little CPU time as possible.
The useless instruction is just before a label and the label is aligned. It looks like a kind of nop
to me (assemblers can generate one-instruction nop
of various lengths because it's more efficient than several of the "standard" one-byte nop
when execution has to go through them).
Your guess is correct. That instruction is effectively a 7-byte NOP to align the label at the start of the loop to a 16-byte boundary. If you were to look at the actual encoding of that instruction, you'd probably notice that not only does it not have any effect on any register or flag, it also uses a 4-byte encoding for the immediate offset of 0 when it could just as easily use a shorter encoding. All of this is to consume the right number of code bytes while making the instruction as efficient to execute as possible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With