/*********************************************/
TEXT: C程序的机器级表示
AUTHOR: arden chao
DATE: 2006-10-17
EMAIL: arden1019@gmail.com
VERSION:1.0.0
/*********************************************/
/
//2006-10-25 陷入寻址模式
//
计算机的寻址模式很复杂
(
我觉得
)
。我也陷入其中了,今天不写了。
/
//2006-11-06 过程控制
//
int fun_int(int x,int y)
{
if(x>y)
x=x-y;
else
x=y-x;
}
// command : gcc -S asm03.c
.file "asm03.c"
.text
.globl _fun_int
.def _fun_int; .scl 2; .type 32; .endef
_fun_int:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
cmpl 12(%ebp), %eax
jle L2
movl 12(%ebp), %eax
subl %eax, 8(%ebp)
jmp L3
L2:
movl 8(%ebp), %eax
movl 12(%ebp), %edx
subl %eax, %edx
movl %edx, %eax
movl %eax, 8(%ebp)
L3:
popl %ebp
ret
cmpl 12(%ebp), %eax ;这条语句对x和y进行比较
jle L2 ;如果y<x就跳到L2去
正是上面两句完成了if的功能,说起来,这种程序流程的跳转,我们分成两种,一种叫做无条件的条转,一种叫做条件跳转。带if的是条件跳转,goto是无条件的。
可以看看下面的代码了解其中差别:
// filename:asm04.c
/*if and goto*/
int fun_goto(int a)
{
if ( a > 1 )
{
a++;
goto end;
}
a--;
end:
return a;
}
// command : gcc -S asm04.c
.file "asm04.c"
.text
.globl _fun_goto
.def _fun_goto; .scl 2; .type 32; .endef
_fun_goto:
pushl %ebp
movl %esp, %ebp
cmpl $1, 8(%ebp)
jle L2
incl 8(%ebp)
jmp L3
L2:
decl 8(%ebp)
L3:
movl 8(%ebp), %eax
popl %ebp
ret
其实,回顾一下我们上面的两个程序来看,if可以按照下面的描述来表示:(自CSAPP)
if(test-expr)
then-statement
else
else-statement
==>
t=test-expr;
if(t)
goto true;
else-statement
goto done;
true:
then-statement
done:
下面是循环:
其实,循环基本上就是if语句加上一个goto。这个不用细说了吧。我们专门对for做一些认识。
for(init-expr;test-expr;update-expr)
body-statement;
可以用下面的while来表示:
init-expr;
while(test-expr)
{
body-statement;
update-expr;
}
再展开到goto:
init-expr;
t=test-expr;
if(!t)
goto done;
loop:
body-statement;
update-expr;
t=test-expr;
if(t)
goto loop;
done:
顺便我们来看看一种提高for循环效率的方法.
看下面代码:
// filename:asm05.c
/*two for function*/
void fun_for1(char *s)
{
int i;
for(i=0;i<strlen(s);i++)
{
s[i]=0;
}
}
void fun_for2(char *s)
{
int i,j;
j=strlen(s);
for(i=0;i<j;i++)
{
s[i]=0;
}
}
// command : gcc -S asm05.c
.file "asm05.c"
.text
.globl _fun_for1
.def _fun_for1; .scl 2; .type 32; .endef
_fun_for1:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $0, -4(%ebp)
L2:
movl 8(%ebp), %eax
movl %eax, (%esp)
call _strlen
cmpl %eax, -4(%ebp)
jae L1
movl 8(%ebp), %eax
addl -4(%ebp), %eax
movb $0, (%eax)
leal -4(%ebp), %eax
incl (%eax)
jmp L2
L1:
leave
ret
.globl _fun_for2
.def _fun_for2; .scl 2; .type 32; .endef
_fun_for2:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call _strlen
movl %eax, -8(%ebp)
movl $0, -4(%ebp)
L6:
movl -4(%ebp), %eax
cmpl -8(%ebp), %eax
jge L5
movl 8(%ebp), %eax
addl -4(%ebp), %eax
movb $0, (%eax)
leal -4(%ebp), %eax
incl (%eax)
jmp L6
L5:
leave
ret
.def _strlen; .scl 3; .type 32; .endef
我们经常会在代码中使用for(i=0;i<strlen(s);i++)这样的循环来遍历一个字符串。可是,对于某些情况下,strlen的调用会成为我们程序运行的瓶颈。因为,标准库中对于strlen的实现,其实也是遍历了一遍字符串。只调用一次strlen的代码将运行的更快...(大家可以给上面函数传入一个65535长的字符串并打印时间来看看结果)