如何区分 while(1) 和 do while?

逆向工程 拆卸
2021-07-01 09:59:13

如何识别装配while (1)do ... while装配之间的区别

谢谢

1个回答

这个答案假定您要比较while (1)do { } while(1)为简单起见,而是应与其他的条件下工作:

以这两个小 C 程序为例:

只是while

#include <stdio.h>
int main(){
   while(1)
      printf("This is a loop\n");
   return 0;
}

do while

#include <stdio.h>
int main(){
   do
      printf("This is a loop\n");
   while(1);
}

使用 gcc/clang 生成特定于平台的程序集(我在 Intel Mac 上)gcc -S loop.c,我们可以看到调用的差异:

只是while

    .section    __TEXT,__text,regular,pure_instructions
    .macosx_version_min 10, 11
    .globl  _main
    .align  4, 0x90
_main:                                  ## @main
    .cfi_startproc
## BB#0:
    pushq   %rbp
Ltmp0:
    .cfi_def_cfa_offset 16
Ltmp1:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp2:
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    movl    $0, -4(%rbp)
LBB0_1:                                 ## =>This Inner Loop Header: Depth=1
    leaq    L_.str(%rip), %rdi
    movb    $0, %al
    callq   _printf
    movl    %eax, -8(%rbp)          ## 4-byte Spill
    jmp LBB0_1
    .cfi_endproc

    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
    .asciz  "This is a loop\n"


.subsections_via_symbols

do while

    .section    __TEXT,__text,regular,pure_instructions
    .macosx_version_min 10, 11
    .globl  _main
    .align  4, 0x90
_main:                                  ## @main
    .cfi_startproc
## BB#0:
    pushq   %rbp
Ltmp0:
    .cfi_def_cfa_offset 16
Ltmp1:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp2:
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    movl    $0, -4(%rbp)
LBB0_1:                                 ## =>This Inner Loop Header: Depth=1
    leaq    L_.str(%rip), %rdi
    movb    $0, %al
    callq   _printf
    movl    %eax, -8(%rbp)          ## 4-byte Spill
## BB#2:                                ##   in Loop: Header=BB0_1 Depth=1
    movb    $1, %al
    testb   $1, %al
    jne LBB0_1
    jmp LBB0_3
LBB0_3:
    movl    -4(%rbp), %eax
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc

    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
    .asciz  "This is a loop\n"


.subsections_via_symbols

请注意LBB0_3do while代码生成的额外子例程我们得到了额外的 Jump Not Equal 指令,因为我们需要在执行whiledo块中的语句后检查表达式的条件是否已经满足

这是关于堆栈溢出的有用资源:while(true) / while(1) vs. for(;;)

正如 Igor Skochinsky 在评论中提到的,使用优化 ( -O3)编译每个程序将为您提供完全相同的程序集。虽然这个练习是在没有优化的小程序上完成的,但实际上,两个循环完成相同的事情并且(取决于编译器)可能会生成相同的程序集。实际上,很难(如果不是不可能的话)区分使用while(1)的循环do { } while(1),因为它们都做同样的事情。