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

可能经常看汇编的朋友会一眼就认出跟C语言中一些语句等价的汇编代码, 经验使然也. 而不经常接触汇编的同学, 可能就对相对繁琐的寄存器操作指令有点云里雾里了.

汇编是编译器翻译中级语言(也可以把C语言称作高级语言, 呵呵)的结果, 只要是机器做的事儿,一般都有规律可循. 那我们现在就来看看一下这些基本语句的汇编规律吧.

注意:本文使用的汇编格式为GAS(Gnu ASembler GNU汇编器). 它同Intel文档中的格式以及微软编译器使用的格式差异很大,

条件转移语句- if

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

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

if(test-expr)

then-statement;

else

else-statement;

对于这种通用形式, 汇编实现通常会使用下面这种形式

t= test-expr;

if (t)

goto true;

else-statement

goto done;

true:

then-statement

done:

也就是汇编器为then-statement 和else-statement各自产生代码块, 并插入条件和无条件分支, 以保证正确代码块的执行.

下面我们来看C语言源代码, 汇编结构的C代码, 和汇编代码的比较.

//----------Classic C code------------

intabsdiff(intx,inty)

{

if(x 

returny - x;

else

returnx - y;

}

//----------Classic C code------------

//----------Equivalent Goto Version------------

intgotodiff(intx,inty)

{

intrval;

if(x 

gotoless;

rval = x - y;

gotodone;

less:

rval = y - x;

done:

returnrval;

}

//----------Equivalent Goto Version------------

//----------Equivalent assembly Version------------

movl 8(%ebp),%edx          ;Get x

movl 12(%ebp),%eax         ;Get y

cmpl %eax,%edx             ;Compare x:y

jl .L3                     ;If 

subl %eax,%edx             ;Compute y-x

movl %edx,%eax             ;Set as returnvalue

jmp .L5                    ;Goto done:

.L3:                           ;less:

subl %edx,%eax             ;Compute x-y as returnvalue

.L5:                           ;done:Begin completion code

//----------Equivalent assembly Version------------

do-while循环

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

do-while循环的通用形式是这样的:

do

{body-statement}

while (test-expr);

循环的效果就是重复执行body-statement, 对test-expr求值, 如果不是0, 就继续循环. 注意, 循环体至少执行一次.

通常, do-while 的实现有下面的通用形式:

loop:

body-statement

t= test-expr;

if (t)

goto loop;

下面是一个例子, 找找感觉吧.

//----------Original C Version------------

do{

intt = val + nval;

val = nval;

nval = t;

i++;

} while(i 

//----------Original C Version------------

//----------Corresponding assembly code------------

.L6: loop:

leal (%edx,%ebx),%eax ;Compute t = val + nval

movl %edx,%ebx        ;copy nval to val

movl %eax,%edx        ;Copy t to nval

incl %ecx             ;Increment i

cmpl %esi,%ecx        ;Compare i:n

jl .L6 If less,       ;gotoloop

//---------Corresponding assembly code------------

while循环

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

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

while(test-expr)

body-statement

与do-while的不同之处在于对test-expr求值, 在第一次执行body-statement之前, 循环就可能终止了. 翻译成goto语句的形式就是

loop:

t= test-expr;

if (!t)

goto done;

body-statement

goto loop;

done:

这种翻译需要在内循环(也就是执行次数最多的代码部分)中, 有两条goto语句. 大多数的编译器将这段代码转换成do-while循环, 把一个条件分支语句从循环体中拿到外面来.

if (!test-expr)

goto done;

do

body-statement

while (test-expr);

done:

然后, 再把这段代码换成带goto的语句的代码, 如下

t= test-expr;

if (!t)

goto done;

loop:

body-statement

t= test-expr;

if (t)

goto loop;

done:

for循环

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

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

for (init-expr; test-expr; update-expr)

body-statement

C语言的标准说明, 这样的一个循环的行为与下面这段使用while循环的代码的行为一样:

init-expr;

while (test-expr){

body-statement

update-expr;

}

然后再用前面讲过的从while到do-while的转换. 首先给出do-while形式

init-expr;

if (!test-expr)

goto done;

do{

body-statement

update-expr;

}while (test-expr);

done:

再转换成goto代码

init-expr;

t= test-expr;

if (!t)

goto done;

loop:

body-statement

update-expr;

t= test-expr;

if (t)

goto loop;

done:

相信现在, 你已经对汇编中的循环指令簇有点模式的感觉了吧? 呵呵. 我们再来看一个switch语句, 然后收工.

switch语句

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

switch语句提供了一个整数索引值, 通过它来进行多重分支. 那么switch语句和一组很长的if-else语句相比, 有什么优势呢? 我先把答案说出来, 然后看看汇编, 就知道了.

优势就是: 执行开关语句的时间与开关情况的数量无关.

能做到这样的原因是跳转表. 跳转表是一个数组, 表项i是一个代码段的地址, 这个代码段实现的就是开关索引值等于i的时候应该采取的动作.

让我们来看一个例子, 这个例子包含一些很有意思的特征, 情况标号(case label)不连续, 比如101, 105; 一个情况有多个标号, 比如104, 106; 有些情况会落入其他情况(102), 因为该情况没有用break结尾.

//----------Original C code------------

intswitch_eg(intx)

{

intresult = x;

switch(x) {

case100:

result *= 13;

break;

case102:

result += 10;

/* Fall through */

case103:

result += 11;

break;

case104:

case106:

result *= result;

break;

default:

result = 0;

}

returnresult;

}

//----------Original C code------------

说明问题的C的伪代码

/* Next line is not legal C */

code *jt[7] = {

loc_A, loc_def, loc_B, loc_C,

loc_D, loc_def, loc_D

};

intswitch_eg_impl(intx)

{

unsigned xi = x - 100;

intresult = x;

if(xi > 6)

gotoloc_def;

/* Next goto is not legal C */

gotojt[xi];

loc_A: /* Case 100 */

result *= 13;

gotodone;

loc_B: /* Case 102 */

result += 10;

/* Fall through */

loc_C: /* Case 103 */

result += 11;

gotodone;

loc_D: /* Cases 104, 106 */

result *= result;

gotodone;

loc_def: /* Default case*/

result = 0;

done:

returnresult;

}

//----------Corresponding assembly code------------

//***********

// Code that Set up the jump table access

//***********

leal -100(%edx),%eax         ;Compute xi = x-100

cmpl $6,%eax                 ;Compare xi:6

ja .L9                       ;if>,gotodone

jmp *.L10(,%eax,4)           ;Goto jt[xi]

//Case 100

L4:                              ;loc A:

leal (%edx,%edx,2),%eax      ;Compute 3*x

leal (%edx,%eax,4),%edx      ;Compute x+4*3*x

jmp .L3                      ;Goto done

//Case 102

L5:                              ;loc B:

addl $10,%edx                ;result += 10, Fall through

//Case 103

L6:                              ;loc C:

addl $11,%edx                ;result += 11

jmp .L3                      ;Goto done

//Cases 104, 106

L8:                              ;loc D:

imull %edx,%edx              ;result *= result

jmp .L3                      ;Goto done

//Default case

L9:                              ;loc def:

xorl %edx,%edx               ;result = 0

//Return result

L3:                              ;done:

movl %edx,%eax               ;Set result as returnvalue

//----------Corresponding assembly code------------

参考资料

(awpatp)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值