C语言到汇编-控制流

C语言控制流程的语句有if-else 语句、switch 语句、while循环、for循环等,先来看一个if-else 的例子。

main() 
{ 
  int x = 7;
  int y = 9;
  float z = 0;
  if(x > y)
      z = x + y;
  else
      z = x - y;
  printf("%f", z);
  return 0;
}

这段代码中由于x 和y 都是固定值,所以执行的肯定是else 分支。来看编译后的汇编代码(去掉不关心部分,后面同):

    .section .rdata,"dr"
LC1:
    .ascii "%f\0"
    .text
_main:
    mov DWORD PTR [ebp-4], 7
    mov DWORD PTR [ebp-8], 9
    mov eax, 0x00000000
    mov DWORD PTR [ebp-12], eax
    mov eax, DWORD PTR [ebp-4]
    cmp eax, DWORD PTR [ebp-8]
    jle L2
    mov eax, DWORD PTR [ebp-8]
    add eax, DWORD PTR [ebp-4]
    push    eax
    fild    DWORD PTR [esp]
    lea esp, [esp+4]
    fstp    DWORD PTR [ebp-12]
    jmp L3
L2:
    mov edx, DWORD PTR [ebp-8]
    mov eax, DWORD PTR [ebp-4]
    sub eax, edx
    push    eax
    fild    DWORD PTR [esp]
    lea esp, [esp+4]
    fstp    DWORD PTR [ebp-12]
L3:
    fld DWORD PTR [ebp-12]
    fstp    QWORD PTR [esp+4]
    mov DWORD PTR [esp], OFFSET FLAT:LC1
    call    _printf
    mov eax, 0
    leave
    ret

由基础汇编知识以及上一篇内容很容易看出,实现if-else 语句用的是比较指令cmp 与各种条件转移指令。具体代码不再分析,由于出现了新的条件转移指令jle ,下面重新总结一下。

根据两个无符号数的比较结果判断转移的指令:
指令            转移条件        含义        英文表述
JA/JNBE DEST    CF=0 AND ZF=0   无符号数A>B JMP above (not below or equal)
JAE/JNB DEST    CF=0            无符号数A≥B JMP above or equal (not below)
JB/JNAE DEST    CF=1            无符号数AB JMP greater (not less or equal)
JGE/JNL DEST    SF=OF OR ZF=1   有符号数A≥B JMP greater or equal (not less)
JL/JNGE DEST    SF≠OF AND ZF=0  有符号数A

以上参照百度百科词条“条件转移指令”。

C语言中其它控制流程的语句编译后也是基于同样的汇编指令,都是cmp 比较,然后各种转移。下面合起来看一个例子:

/* 各种控制流程语句:if-else-if; switch; while; for; do-while; break; continue; goto */
#include  
int main() 
{ 
// if-else 语句
  int a = 7;
  int c = getchar();
  if(c >= '0' && c <= '9'){
      c ++;
      a += c;  
      printf("a = %d\n", a);
  }else if(c == 'A'){
      printf("is A\n");
  }else{
      printf("%d\n", c);
  }

  // switch 语句
  c = getchar();
  switch(c){
      case 'A':
      printf("AAA");
      break;  // break语句
      case 'B':
      printf("BBB");
      case 'C':
      printf("CCC");
      break;
      default:
      printf("DDD");
      break;
  }
  
// while循环
  while((c=getchar()) != 'q'){
      printf("%d", c);
  }
  
  int i;
  for(i=0; i<10; i++){
      if(i==5)
          continue;  // continue语句
      printf("%d", i); 
  }
  
// do-while循环
  do{
      printf("do-while\n");
      break;
  }while(1);
  
// for循环
  for(;;){
      for(i=0; i<100; i++){
          printf("%d", i);
          if(i==50)
              goto somewhere;  // goto语句
      }
  }
  
  somewhere:
  printf("end");
  return 0;
}

编译后的汇编代码:

    .section .rdata,"dr"  //将后续的代码汇编进一个定名为.rdata的段。
LC0:
    .ascii "a = %d\12\0"
LC1:
    .ascii "is A\12\0"
LC2:
    .ascii "%d\12\0"
LC3:
    .ascii "AAA\0"
LC4:
    .ascii "BBB\0"
LC5:
    .ascii "CCC\0"
LC6:
    .ascii "DDD\0"
LC7:
    .ascii "%d\0"
LC8:
    .ascii "do-while\12\0"
LC9:
    .ascii "end\0"
    .text  //将后续语句汇编到编号为0的子段。
_main:
    mov DWORD PTR [ebp-4], 7
    call    _getchar
    mov DWORD PTR [ebp-8], eax
    cmp DWORD PTR [ebp-8], 47
    jle L2
    cmp DWORD PTR [ebp-8], 57
    jg  L2
    lea eax, [ebp-8]
    inc DWORD PTR [eax]
    mov edx, DWORD PTR [ebp-8]
    lea eax, [ebp-4]
    add DWORD PTR [eax], edx
    mov eax, DWORD PTR [ebp-4]
    mov DWORD PTR [esp+4], eax
    mov DWORD PTR [esp], OFFSET FLAT:LC0
    call    _printf
    jmp L3
L2:
    cmp DWORD PTR [ebp-8], 65
    jne L4
    mov DWORD PTR [esp], OFFSET FLAT:LC1
    call    _printf
    jmp L3
L4:
    mov eax, DWORD PTR [ebp-8]
    mov DWORD PTR [esp+4], eax
    mov DWORD PTR [esp], OFFSET FLAT:LC2
    call    _printf
L3:
    call    _getchar
    mov DWORD PTR [ebp-8], eax
    mov eax, DWORD PTR [ebp-8]
    mov DWORD PTR [ebp-16], eax
    cmp DWORD PTR [ebp-16], 66
    je  L8
    cmp DWORD PTR [ebp-16], 66
    jg  L11
    cmp DWORD PTR [ebp-16], 65
    je  L7
    jmp L10
L11:
    cmp DWORD PTR [ebp-16], 67
    je  L9
    jmp L10
L7:
    mov DWORD PTR [esp], OFFSET FLAT:LC3
    call    _printf
    jmp L12
L8:
    mov DWORD PTR [esp], OFFSET FLAT:LC4
    call    _printf
L9:
    mov DWORD PTR [esp], OFFSET FLAT:LC5
    call    _printf
    jmp L12
L10:
    mov DWORD PTR [esp], OFFSET FLAT:LC6
    call    _printf
L12:
    call    _getchar
    mov DWORD PTR [ebp-8], eax
    cmp DWORD PTR [ebp-8], 113
    je  L13
    mov eax, DWORD PTR [ebp-8]
    mov DWORD PTR [esp+4], eax
    mov DWORD PTR [esp], OFFSET FLAT:LC7
    call    _printf
    jmp L12
L13:
    mov DWORD PTR [ebp-12], 0
L14:
    cmp DWORD PTR [ebp-12], 9
    jg  L18
    cmp DWORD PTR [ebp-12], 5
    jne L17
    jmp L16
L17:
    mov eax, DWORD PTR [ebp-12]
    mov DWORD PTR [esp+4], eax
    mov DWORD PTR [esp], OFFSET FLAT:LC7
    call    _printf
L16:
    lea eax, [ebp-12]
    inc DWORD PTR [eax]
    jmp L14
L18:
    mov DWORD PTR [esp], OFFSET FLAT:LC8
    call    _printf
L20:
    mov DWORD PTR [ebp-12], 0
L22:
    cmp DWORD PTR [ebp-12], 99
    jg  L20
    mov eax, DWORD PTR [ebp-12]
    mov DWORD PTR [esp+4], eax
    mov DWORD PTR [esp], OFFSET FLAT:LC7
    call    _printf
    cmp DWORD PTR [ebp-12], 50
    jne L24
    jmp L26
L24:
    lea eax, [ebp-12]
    inc DWORD PTR [eax]
    jmp L22
L26:
    mov DWORD PTR [esp], OFFSET FLAT:LC9
    call    _printf
    mov eax, 0
    leave
    ret

上面这段虽然代码很长,但和前面的if-else 汇编代码基本没什么区别,就是跳转次数多了些而已。
好了,C语言的控制流程语句就先学到这里,下一篇开始学习第4章,函数与结构。

你可能感兴趣的:(C语言到汇编-控制流)