为什么使用JLE代替JL?

ely*_*hiv 10 c compiler-construction assembly

我写了以下程序:

#include <stdio.h>

int main()
{
    int i = 0;
    for (; i < 4; i++)
    {
        printf("%i",i);
    }

    return 0;
} 
Run Code Online (Sandbox Code Playgroud)

我使用gcc test.c -o test.o它编译它,然后使用它进行反汇编objdump -d -Mintel test.o.我得到的汇编代码(至少是相关部分)如下:

0804840c <main>:
 804840c:   55                      push   ebp
 804840d:   89 e5                   mov    ebp,esp
 804840f:   83 e4 f0                and    esp,0xfffffff0
 8048412:   83 ec 20                sub    esp,0x20
 8048415:   c7 44 24 1c 00 00 00    mov    DWORD PTR [esp+0x1c],0x0
 804841c:   00 
 804841d:   eb 19                   jmp    8048438 <main+0x2c>           
 804841f:   8b 44 24 1c             mov    eax,DWORD PTR [esp+0x1c]
 8048423:   89 44 24 04             mov    DWORD PTR [esp+0x4],eax
 8048427:   c7 04 24 e8 84 04 08    mov    DWORD PTR [esp],0x80484e8
 804842e:   e8 bd fe ff ff          call   80482f0 <printf@plt>
 8048433:   83 44 24 1c 01          add    DWORD PTR [esp+0x1c],0x1
 8048438:   83 7c 24 1c 03          cmp    DWORD PTR [esp+0x1c],0x3
 804843d:   7e e0                   jle    804841f <main+0x13>
 804843f:   b8 00 00 00 00          mov    eax,0x0
 8048444:   c9                      leave  
 8048445:   c3                      ret
Run Code Online (Sandbox Code Playgroud)

我注意到,虽然我的比较操作是i < 4,但汇编代码是(在反汇编之后)i <= 3.为什么会这样?为什么要使用JLE而不是JL

ana*_*lyg 6

向上计数并且具有恒定限制的循环非常常见.编译器有两个选项来实现循环终止检查 - JLEJL.虽然这两种方式看起来完全相同,但请考虑以下几点.

正如您在反汇编列表中看到的那样,常量(3在您的情况下)以1个字节编码.如果您的循环计数为256而不是4,那么就不可能CMP指令使用这种有效的编码,并且编译器必须使用"更大"的编码.因此JLE,代码密度提供了微小的改进(由于缓存,最终有利于提高性能).