编译代码中的冗余指令

时间:2011-11-02 21:36:56

标签: visual-c++ compiler-construction assembly x86

  

可能重复:
  What's the point of LEA EAX, [EAX]?

在反汇编练习中,我观察到以下代码:

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;
}

使用vc ++ 2008进行优化编译:

cl /Ox test.cpp

主要功能的反汇编:

.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

现在,我不是一个专家,正如你可以从示例代码中看到的那样,但考虑到我编写了原始代码,我能够弄清楚这个汇编列表。唯一困扰我的是以下几行:

.text:00401019                 lea     esp, [esp+0]

为什么编译器会这样做?它不会影响任何寄存器或标志,它看起来像冗余代码。我唯一能想到的是编译器在第二个循环中对齐jmp所在的代码(loc_401020)这可能是原因吗?

3 个答案:

答案 0 :(得分:3)

是的,看起来它正在插入填充以对齐跳跃目标。如果使用/Fa让编译器生成汇编输出,那么它将显示为npad 7,明确表示它正在插入填充。从那里开始,由汇编程序选择最有效的指令序列,它可以在尽可能少的CPU时间内使用指定的空间。

答案 1 :(得分:1)

无用指令就在标签之前,标签对齐。对我来说它看起来像nop(汇编程序可以生成各种长度的单指令nop,因为它比执行时的几个“标准”单字节nop更有效。通过它们。)

答案 2 :(得分:1)

你的猜测是正确的。该指令实际上是一个7字节的NOP,用于将循环开始处的标签与16字节边界对齐。如果您要查看该指令的实际编码,您可能会注意到它不仅对任何寄存器或标志没有任何影响,它还会使用4字节编码来实现0的立即偏移量。就像使用较短的编码一样容易。所有这些都是消耗正确数量的代码字节,同时使指令尽可能高效地执行。