菜单

赶快识别汇编中等价的C语言语句(if, while, for, switch)

2019年7月11日 - 皇家赌场系统

兴许时时看汇编的心上人会一眼就认出跟C语言中部分话语等价的汇编代码,
经验使然也. 而不平时接触汇编的校友,
恐怕就对相对繁琐的寄放器操作指令有点云里雾里了.

汇编是编写翻译器翻译中级语言(也能够把C语言称作高档语言, 呵呵)的结果,
只借使机械做的事体,一般都有规律可循.
那大家后天就来看看一下那一个基本语句的汇编规律吧.

只顾:本文使用的汇编格式为GAS(Gnu ASembler GNU汇编器).
它同速龙文书档案中的格式以及微软编写翻译器使用的格式差距相当的大,

具体请看小说AT&T汇编格式与AMD汇编格式的相比.

 

规范化转移语句- if

============================

C语言中的if-else语句的通用方式如下

  1. if(test-expr)
  2.     then-statement;
  3. else
  4.     else-statement;

对此这种通用方式, 汇编实现普通会利用上边这种样式

  1.     t= test-expr;
  2.     if (t)
  3.         goto true;
  4.     else-statement
  5.         goto done;
  6. true:
  7.     then-statement
  8. done:

也正是汇编器为then-statement 和else-statement各自行爆炸发代码块,
并插入条件和无需付费分支, 以保证科学代码块的实践.

 

下边大家来看C语言源代码, 汇编结构的C代码, 和汇编代码的比较.

Code Snippet

  1. //———-Classic C code————
  2. int absdiff(int x, int y)
  3. {
  4.     if (x < y)
  5.         return y – x;
  6.     else
  7.         return x – y;
  8. }
  9. //———-Classic C code————

 

Code Snippet

  1. //———-Equivalent Goto Version————
  2. int gotodiff(int x, int y)
  3. {
  4.     int rval;
  5.  
  6.     if (x < y)
  7.         goto less;
  8.     rval = x – y;
  9.     goto done;
  10. less:
  11.     rval = y – x;
  12. done:
  13.     return rval;
  14. }
  15. //———-Equivalent Goto Version————

 

Code Snippet

  1. //———-Equivalent assembly Version————
  2.     movl 8(%ebp),%edx          ;Get x
  3.     movl 12(%ebp),%eax         ;Get y
  4.     cmpl %eax,%edx             ;Compare x:y
  5.     jl .L3                     ;If <, goto less:
  6.     subl %eax,%edx             ;Compute y-x
  7.     movl %edx,%eax             ;Set as return value
  8.     jmp .L5                    ;Goto done:
  9. .L3:                           ;less:
  10.     subl %edx,%eax             ;Compute x-y as return value
  11. .L5:                           ;done:Begin completion code
  12. //———-Equivalent assembly Version————

 

do-while循环

========================

do-while循环的通用格局是那样的:

  1. do
  2. {body-statement}
  3. while (test-expr);

循环的成效就是重复推行body-statement, 对test-expr求值, 假使不是0,
就继续循环. 注意, 循环体至少推行一遍.

普通, do-while 的落到实处有上面的通用方式:

  1. loop:
  2.     body-statement
  3.     t= test-expr;
  4.     if (t)
  5.         goto loop;

皇家编程, 

上面是贰个事例, 找找认为吧.

Code Snippet

  1. //———-Original C Version————
  2. do{
  3.     int t = val + nval;
  4.     val = nval;
  5.     nval = t;
  6.     i++;
  7. } while (i < n);
  8. //———-Original C Version————

 

Code Snippet

  1. //———-Corresponding assembly code————
  2. .L6: loop:
  3.     leal (%edx,%ebx),%eax ;Compute t = val + nval
  4.     movl %edx,%ebx        ;copy nval to val
  5.     movl %eax,%edx        ;Copy t to nval
  6.     incl %ecx             ;Increment i
  7.     cmpl %esi,%ecx        ;Compare i:n
  8.     jl .L6 If less,       ;goto loop
  9. //———Corresponding assembly code————

 

while循环

========================

while语句循环的通用形式是这么的

  1. while(test-expr)
  2.     body-statement

与do-while的不一致之处在于对test-expr求值, 在首先次举行body-statement在此以前,
循环就也许终止了. 翻译成goto语句的格局就是

  1. loop:
  2.     t= test-expr;
  3.     if (!t)
  4.         goto done;
  5.     body-statement
  6.         goto loop;
  7. done:

这种翻译须要在内循环(也正是施行次数最多的代码部分)中, 有两条goto语句.
大多数的编写翻译器将这段代码转换到do-while循环,
把贰个规格分支语句从循环体中获得外边来.

  1.     if (!test-expr)
  2.         goto done;
  3.     do
  4.     body-statement
  5.         while (test-expr);
  6. done:

接下来, 再把这段代码换来带goto的言辞的代码, 如下

  1.     t= test-expr;
  2.     if (!t)
  3.         goto done;
  4. loop:
  5.     body-statement
  6.         t= test-expr;
  7.     if (t)
  8.         goto loop;
  9. done:

 

for循环

========================

for循环的通用方式是这样的:

  1. for (init-expr; test-expr; update-expr)
  2.     body-statement

C语言的行业内部认证,
那样的一个生生不息的行事与下部这段使用while循环的代码的表现一律:

  1. init-expr;
  2. while (test-expr){
  3.     body-statement
  4.     update-expr;
  5. }

然后再用前边讲过的从while到do-while的调换. 首先付诸do-while情势

  1.     init-expr;
  2.     if (!test-expr)
  3.         goto done;
  4.     do{
  5.         body-statement
  6.         update-expr;
  7.     }while (test-expr);
  8. done:

再调换到goto代码

  1.     init-expr;
  2.     t= test-expr;
  3.     if (!t)
  4.         goto done;
  5. loop:
  6.     body-statement
  7.         update-expr;
  8.     t= test-expr;
  9.     if (t)
  10.         goto loop;
  11. done:

 

相信未来, 你早已对汇编中的循环指令簇有一点点方式的认为到了啊? 呵呵.
大家再来看多少个switch语句, 然后收工.

switch语句

======================

switch语句提供了一个整数索引值, 通过它来举行多种分支.
那么switch语句和一组非常短的if-else语句相比较, 有何优势呢?
笔者先把答案说出去, 然后看看汇编, 就明白了.

优势便是: 实行按键语句的时刻与按键情状的数额非亲非故.

能成就那样的缘由是跳转表. 跳转表是贰个数组, 表项i是多个代码段的地址,
那个代码段完成的即是按钮索引值等于i的时候应该运用的动作.

 

让我们来看贰个例子, 这么些例子包括部分很有意思的特点, 情形标号(case
label)不总是, 比方101, 105; 一个情景有两个标号, 譬喻104, 106;
某些境况会落入其余意况(102), 因为该情况未有用break结尾.

  1. //———-Original C code————
  2. int switch_eg(int x)
  3. {
  4.     int result = x;
  5.  
  6.     switch (x) {
  7.  
  8.         case 100:
  9.             result *= 13;
  10.             break;
  11.  
  12.         case 102:
  13.             result += 10;
  14.             /* Fall through */
  15.  
  16.         case 103:
  17.             result += 11;
  18.             break;
  19.  
  20.         case 104:
  21.         case 106:
  22.             result *= result;
  23.             break;
  24.  
  25.         default:
  26.             result = 0;
  27.     }
  28.  
  29.     return result;
  30. }
  31. //———-Original C code————

证明难点的C的伪代码

  1. /* Next line is not legal C */
  2. code *jt[7] = {
  3.     loc_A, loc_def, loc_B, loc_C,
  4.     loc_D, loc_def, loc_D
  5. };
  6. int switch_eg_impl(int x)
  7. {
  8.     unsigned xi = x – 100;
  9.     int result = x;
  10.     if (xi > 6)
  11.         goto loc_def;
  12.     /* Next goto is not legal C */
  13.     goto jt[xi];
  14. loc_A: /* Case 100 */
  15.     result *= 13;
  16.     goto done;
  17. loc_B: /* Case 102 */
  18.     result += 10;
  19.     /* Fall through */
  20. loc_C: /* Case 103 */
  21.     result += 11;
  22.     goto done;
  23. loc_D: /* Cases 104, 106 */
  24.     result *= result;
  25.     goto done;
  26. loc_def: /* Default case*/
  27.     result = 0;
  28. done:
  29.     return result;
  30. }

 

  1. //———-Corresponding assembly code————
  2. //***********
  3. // Code that Set up the jump table access
  4. //***********
  5.     leal -100(%edx),%eax         ;Compute xi = x-100
  6.     cmpl $6,%eax                 ;Compare xi:6
  7.     ja .L9                       ;if >, goto done
  8.     jmp *.L10(,%eax,4)           ;Goto jt[xi]
  9. //Case 100
  10. L4:                              ;loc A:
  11.     leal (%edx,%edx,2),%eax      ;Compute 3*x
  12.     leal (%edx,%eax,4),%edx      ;Compute x+4*3*x
  13.     jmp .L3                      ;Goto done
  14. //Case 102
  15. L5:                              ;loc B:
  16.     addl $10,%edx                ;result += 10, Fall through
  17. //Case 103
  18. L6:                              ;loc C:
  19.     addl $11,%edx                ;result += 11
  20.     jmp .L3                      ;Goto done
  21. //Cases 104, 106
  22. L8:                              ;loc D:
  23.     imull %edx,%edx              ;result *= result
  24.     jmp .L3                      ;Goto done
  25. //Default case
  26. L9:                              ;loc def:
  27.     xorl %edx,%edx               ;result = 0
  28. //Return result
  29. L3:                              ;done:
  30.     movl %edx,%eax               ;Set result as return value
  31. //———-Corresponding assembly code————

 

参照他事他说加以考察资料<深切明白计算机种类>


相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图