C语言控制流对应的汇编语句
最近在看《深入理解計(jì)算機(jī)系統(tǒng)》,發(fā)現(xiàn)匯編挺有趣。
1.條件分支:if語句
下面是一個(gè)簡(jiǎn)單的ifelse函數(shù):
int absdiff(int x, int y) {if (x < y)return y - x;elsereturn x - y; }對(duì)這個(gè)程序使用如下命令,得到匯編程序,(注意-S選項(xiàng)大寫,并且始終用-O1優(yōu)化選項(xiàng))
gcc -S ifelse.c -o ifelse.s –O1可以看到gcc對(duì)改程序的翻譯與書上略有不同:
pushl %ebx.cfi_def_cfa_offset 8.cfi_offset 3, -8movl 8(%esp), %ecxmovl 12(%esp), %edxmovl %edx, %eaxsubl %ecx, %eaxmovl %ecx, %ebxsubl %edx, %ebxcmpl %edx, %ecxcmovge %ebx, %eaxpopl %ebxgcc中,%ecx: x, %edx:y , %eax: y-x, %ebx: x-y. 比較x與y,若x>=y, %eax: x-y. 最終在%eax中存放result。
其中,cmovge使用了后面將要講到的 條件傳送指令,即先計(jì)算一個(gè)條件操作的兩種結(jié)果,然后再根據(jù)條件是否滿足而選取一個(gè)。它要求處理器類型在i686以上,在gcc中可以添加'-march=i686'來編譯,但是ubuntu11.10的處理器類型就是i686的(使用uname –p查看),所以上面的編譯直接得到采用條件傳送指令的匯編代碼。
使用條件傳送并不總是能改進(jìn)代碼效率,對(duì)GCC來說,只有很容易計(jì)算時(shí)(如只有一條加法指令),它才使用條件傳送指令。
【題外話】:
下面的語句產(chǎn)生條件傳送的匯編代碼:
int arith(int x){return x / 4; }使用-O1選項(xiàng)產(chǎn)生匯編代碼如下:
.cfi_startprocmovl 4(%esp), %eax //get xleal 3(%eax), %edx //temp = x+3testl %eax, %eax cmovs %edx, %eax //if(x < 0) x = tempsarl $2, %eax // return x >> 2ret.cfi_endproc可以看到,如果是負(fù)數(shù),在算術(shù)右移時(shí),要加上2^k-1=3的偏置。注意,這里加偏置的原因:一般來說,我們可以直接對(duì)補(bǔ)碼進(jìn)行右移操作表示2^k冪,但是真正的除法與補(bǔ)碼右移還是有一定區(qū)別的:
真正除法一定是舍入到0,所以-2.5得到-2;補(bǔ)碼右移則會(huì)向下舍入,所以-2.5會(huì)得到-3(因?yàn)樗偸前训臀粊G棄);
所以,在做真正除法時(shí)會(huì)加上一個(gè)偏置值,(原來CS:APP第65頁2.3.7節(jié)講到了這個(gè)問題,哎,可惜跳過去了。。)
int i = -9;cout << i/4 << endl; //get -2cout << (i>>2) << endl; //get -3-9的右移過程如下:得到原碼1001——轉(zhuǎn)為補(bǔ)碼0111——右移兩位1101——轉(zhuǎn)為原碼0011,即得到-3。
-9+偏置3過程: -6原碼 0110——轉(zhuǎn)為補(bǔ)碼1010——右移兩位1110——轉(zhuǎn)為原碼0010,得到-2.
2.循環(huán)
2.1 do-while循環(huán)的翻譯
匯編中的循環(huán)使用 條件測(cè)試和跳轉(zhuǎn) 組合起來實(shí)現(xiàn)。大部分編譯器根據(jù)do-while形式產(chǎn)生循環(huán)代碼,如下求階乘的循環(huán)代碼:
int fact_do(int n) {int result = 1;do{result *= n;n = n-1;}while(n>1);return result; }產(chǎn)生匯編如下:
.cfi_startprocmovl 4(%esp), %edx //get nmovl $1, %eax //set result=1 .L2:imull %edx, %eax // result *= nsubl $1, %edx //n--cmpl $1, %edx //compare n-1jg .L2 //if(n>1): goto .L2repret.cfi_endproc2.2 for循環(huán)的翻譯
// Step1: for循環(huán)語句 for(init-expr; test-expr; update-expr)body-statement;// Step2: while循環(huán)語句 init-expr; while(test-expr){body-statement;update-expr; }// Step3: do-while循環(huán)語句 init-expr; if(!test-expr)goto done do{body-statement;update-expr; }while(test-expr); done:// Step4: goto語句(直觀的展示了匯編代碼實(shí)現(xiàn)) init-expr; if(!test-expr)goto done loop:body-statement;update-expr;if(test-expr)goto loop; done:帶continue語句時(shí)的特例(練習(xí)3.24):
i = 0; while(i < 10){if(i&1)continue; //continue在i++之前,阻止了i的更新sum += i;i++; }i = 0; if(i >= 10)goto done do{if(i&1)continue; //continue在i++之前,阻止了i的更新sum += i;i++; }while(i < 10); done:do-while循環(huán)的continue語句還有一個(gè)問題要注意:
翻譯為do-while循環(huán)時(shí)出現(xiàn)了問題,關(guān)鍵是continue的含義是不執(zhí)行循環(huán)體內(nèi)的內(nèi)容,直接到達(dá)下一個(gè)循環(huán)點(diǎn)(也就是while處的判斷,而不是“do{”處),所以下面語句只會(huì)輸出1.
使用goto語句來保證while循環(huán)的更新(寫代碼時(shí),直接在continue前加一個(gè)i++即可):
while(i < 10){if(i&1)goto next;sum += i; next:i++; }3.switch語句
對(duì)switch的匯編,GCC會(huì)根據(jù)開關(guān)數(shù)量和稀少程度選擇是否使用 跳轉(zhuǎn)表 來翻譯開關(guān)語句。跳轉(zhuǎn)表是一個(gè)數(shù)組,表項(xiàng)i是代碼短的地址,其執(zhí)行時(shí)間與開關(guān)情況的數(shù)量無關(guān)。如下switch語句:
int switch_eg(int x, int n){int result = x;switch(n){case 100:result *= 13;break;case 102:result += 10;case 103:result += 11;break;case 104:case 106:result *= result;break;default:result = 0;}return result; }使用-O1翻譯成匯編為:
.cfi_startprocmovl 4(%esp), %eaxmovl 8(%esp), %edxsubl $100, %edxcmpl $6, %edxja .L8jmp *.L7(,%edx,4).section .rodata.align 4.align 4 .L7:.long .L3.long .L8 //case 101: default.long .L4.long .L5.long .L6.long .L8 //case 105: default.long .L6.text .L3: //case 100: result *= 13leal (%eax,%eax,2), %edx // get 3*xleal (%eax,%edx,4), %eax //get x+4*(3x)= 13*xret .L4: //case 102: result += 10addl $10, %eax .L5: //case 103: result += 11addl $11, %eaxret .L6: //case 104/106: result *= resultimull %eax, %eaxret .L8: //default: result = 0movl $0, %eaxret.cfi_endproc轉(zhuǎn)載于:https://www.cnblogs.com/dandingyy/archive/2013/01/03/2837053.html
總結(jié)
以上是生活随笔為你收集整理的C语言控制流对应的汇编语句的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 设计模式建议学习顺序
- 下一篇: beautiful sentences