/*********************************************/ 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 L3L2: 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 L3L2: decl 8(%ebp)L3: movl 8(%ebp), %eax popl %ebp ret 其實,回顧一下我們上面的兩個程式來看,if可以按照下面的描述來表示:(自CSAPP)if(test-expr) then-statementelse else-statement ==> t=test-expr; if(t) goto true; else-statement goto done;true: then-statementdone: 下面是迴圈:其實,迴圈基本上就是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 L2L1: 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 L6L5: leave ret .def _strlen; .scl 3; .type 32; .endef 我們經常會在代碼中使用for(i=0;i<strlen(s);i++)這樣的迴圈來遍曆一個字串。可是,對於某些情況下,strlen的調用會成為我們程式啟動並執行瓶頸。因為,標準庫中對於strlen的實現,其實也是遍曆了一遍字串。只調用一次strlen的代碼將啟動並執行更快...(大家可以給上面函數傳入一個65535長的字串並列印時間來看看結果)