快速识别汇编中等价的C语言语句(if, while, for, switch)
2012-07-16 22:18
706 查看
可能经常看汇编的朋友会一眼就认出跟C语言中一些语句等价的汇编代码, 经验使然也. 而不经常接触汇编的同学, 可能就对相对繁琐的寄存器操作指令有点云里雾里了.
汇编是编译器翻译中级语言(也可以把C语言称作高级语言, 呵呵)的结果, 只要是机器做的事儿,一般都有规律可循. 那我们现在就来看看一下这些基本语句的汇编规律吧.
注意:本文使用的汇编格式为GAS(Gnu ASembler GNU汇编器). 它同Intel文档中的格式以及微软编译器使用的格式差异很大,
具体请看文章AT&T汇编格式与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代码, 和汇编代码的比较.
Code Snippet
//----------Classic C code------------
int
absdiff(int
x, int y)
{
if (x <
y)
return
y - x;
else
return
x - y;
}
//----------Classic C code------------
Code Snippet
//----------Equivalent Goto Version------------
int
gotodiff(int
x, int y)
{
int
rval;
if (x <
y)
goto less;
rval =
x - y;
goto done;
less:
rval = y -
x;
done:
return rval;
}
//----------Equivalent Goto Version------------
Code Snippet
//----------Equivalent assembly Version------------
movl 8(%ebp),%edx ;Get
x
movl 12(%ebp),%eax ;Get
y
cmpl %eax,%edx ;Compare
x:y
jl .L3 ;If <,
goto less:
subl %eax,%edx ;Compute
y-x
movl %edx,%eax ;Set
as return
value
jmp .L5 ;Goto
done:
.L3: ;less:
subl %edx,%eax ;Compute
x-y
as return value
.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;
下面是一个例子, 找找感觉吧.
Code Snippet
//----------Original C Version------------
do{
int t =
val + nval;
val =
nval;
nval = t;
i++;
} while (i <
n);
//----------Original C Version------------
Code Snippet
//----------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, ;goto
loop
//---------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------------
int
switch_eg(int
x)
{
int
result = x;
switch (x) {
case 100:
result *= 13;
break;
case 102:
result += 10;
/* Fall through */
case 103:
result += 11;
break;
case 104:
case 106:
result *=
result;
break;
default:
result = 0;
}
return result;
}
//----------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
};
int
switch_eg_impl(int
x)
{
unsigned
xi = x - 100;
int result =
x;
if (xi > 6)
goto loc_def;
/* Next goto is not legal C */
goto jt[xi];
loc_A:
/* Case 100 */
result *= 13;
goto
done;
loc_B: /* Case 102 */
result += 10;
/* Fall through */
loc_C:
/* Case 103 */
result += 11;
goto
done;
loc_D: /* Cases 104, 106 */
result *=
result;
goto done;
loc_def:
/* Default case*/
result = 0;
done:
return result;
}
//----------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 >,
goto done
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
return value
//----------Corresponding assembly code------------
汇编是编译器翻译中级语言(也可以把C语言称作高级语言, 呵呵)的结果, 只要是机器做的事儿,一般都有规律可循. 那我们现在就来看看一下这些基本语句的汇编规律吧.
注意:本文使用的汇编格式为GAS(Gnu ASembler GNU汇编器). 它同Intel文档中的格式以及微软编译器使用的格式差异很大,
具体请看文章AT&T汇编格式与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代码, 和汇编代码的比较.
Code Snippet
//----------Classic C code------------
int
absdiff(int
x, int y)
{
if (x <
y)
return
y - x;
else
return
x - y;
}
//----------Classic C code------------
Code Snippet
//----------Equivalent Goto Version------------
int
gotodiff(int
x, int y)
{
int
rval;
if (x <
y)
goto less;
rval =
x - y;
goto done;
less:
rval = y -
x;
done:
return rval;
}
//----------Equivalent Goto Version------------
Code Snippet
//----------Equivalent assembly Version------------
movl 8(%ebp),%edx ;Get
x
movl 12(%ebp),%eax ;Get
y
cmpl %eax,%edx ;Compare
x:y
jl .L3 ;If <,
goto less:
subl %eax,%edx ;Compute
y-x
movl %edx,%eax ;Set
as return
value
jmp .L5 ;Goto
done:
.L3: ;less:
subl %edx,%eax ;Compute
x-y
as return value
.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;
下面是一个例子, 找找感觉吧.
Code Snippet
//----------Original C Version------------
do{
int t =
val + nval;
val =
nval;
nval = t;
i++;
} while (i <
n);
//----------Original C Version------------
Code Snippet
//----------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, ;goto
loop
//---------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------------
int
switch_eg(int
x)
{
int
result = x;
switch (x) {
case 100:
result *= 13;
break;
case 102:
result += 10;
/* Fall through */
case 103:
result += 11;
break;
case 104:
case 106:
result *=
result;
break;
default:
result = 0;
}
return result;
}
//----------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
};
int
switch_eg_impl(int
x)
{
unsigned
xi = x - 100;
int result =
x;
if (xi > 6)
goto loc_def;
/* Next goto is not legal C */
goto jt[xi];
loc_A:
/* Case 100 */
result *= 13;
goto
done;
loc_B: /* Case 102 */
result += 10;
/* Fall through */
loc_C:
/* Case 103 */
result += 11;
goto
done;
loc_D: /* Cases 104, 106 */
result *=
result;
goto done;
loc_def:
/* Default case*/
result = 0;
done:
return result;
}
//----------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 >,
goto done
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
return value
//----------Corresponding assembly code------------
相关文章推荐
- 快速识别汇编中等价的C语言语句(if, while, for, switch)
- 快速识别汇编中等价的C语言语句(if, while, for, switch)
- 快速识别汇编中等价的C语言语句(if, while, for, switch)
- C语言中流程控制语句(if,switch,for,while,do-while,continue,break,return)
- C语言控制语句总结(if else for switch while break continue)
- C语言笔试题精选1---求两个数之间较大的数,不使用if、while、switch、for、?:/以及任何比较语句
- C语言奇思妙想:求1+2+…+n,要求不能使用乘除法、for、while、if、else、switch、case 等关键字以及条件判断语句(A?B:C)
- C/C++学习(一)题目:求1+2+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句(A?B:C)。
- 求1+2+…+n, 要求不能使用乘除法、for、while、if、else、switch、case和条件语句
- 求1+2+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句
- JAVA之旅(二)——if,switch,for,while,do while,语句嵌套,流程控制break , continue ,函数,重载的示例总结
- Interview----求 1+2+...+n, 不能用乘除法、for、while if、else、switch、case 等关键字以及条件判断语句 (A?B:C)
- 求1+2+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句(A? B:C)
- Swift第三课 分支语句 if else for forin switch while do-while
- 分支结构、循环结构流控语句(if、switch、for、while)
- Lesson_for_java_day05--java的三目运算符、if语句、switch语句、while循环、for循环
- Interview----求 1+2+...+n, 不能用乘除法、for、while if、else、switch、case 等关键字以及条件判断语句 (A?B:C)
- 两个整数型,不准用while、if、for、switch等判断语句 求出两者最大值
- if,continue,break,while,do-while, switch,return,foreach,for等条件语句的使用
- 求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)