組合語言入門六 流程控制(二)

2021-08-07 06:35:31 字數 3201 閱讀 2204

前面說到在組合語言中實現類似c語言if-else if-else這樣的結構,

實際上,在彙編裡面,我們並不關心if了,取而代之的是兩種基本的指令:

這兩種指令即可組成最基本的分支程式結構,雖然跳轉指令非常多,但是我們已經有套路了,怎麼跳轉都不怕了。當然,在程式設計環境中僅有分支還不夠的,我們知道c語言中除了分支結構之外,還有迴圈這個最基本也是最常用的形式。正好,這也是本節話題的主角。

asm.0x233.com

上回說到c語言中if這樣的結構,在彙編裡對應的是怎麼回事,實質上,這就是分支結構的程式在彙編裡的表現形式。

實際上,迴圈結構相比分支結構,本質上,沒有多少變化,僅僅是比較合跳轉指令的組合的方式與順序有所不同,所以形成了迴圈。

當然,這個說法可能稍微拗口了一點。說得簡單一點,迴圈的乙個關鍵特點就是:

細細想,好像有道理哦,如果程式每到乙個位置就往前跳轉,那就是死迴圈,如果是在這個位置根據條件決定是否要向前跳轉,那就是有條件的迴圈了。

口說無憑,還是先來分析一下乙個c語言的while迴圈:

(talk is chip, show your code!)

int sum = 0;

int i = 1;

while( i <= 10 )

想必這段程式多數人都非常熟悉了,當年自己第一次學習迴圈的時候就碰到這個題目,腦子短路了,心裡總想著這不就是乙個等差數列公式麼,題目卻強行出現在迴圈一章的後面,最後結果讓人大跌眼睛,這是要我老老實實像shab一樣去加啊。

跑題了,先大致總結一下這個程式的關鍵部分到底在幹什麼:

好了,按照這個邏輯,在c語言中不使用迴圈怎麼實現?其實也非常簡單:

int sum = 10;

int i = 1;

_start:

if( i <= 10 )

這還不夠,我們還得做一次變形,為什麼呢?回想一下前面說的分之程式在彙編裡的情況:

if ( a > 10 )

上述c**,暫且成為「正宗c**」,等價的彙編大致結構如下:

cmp eax, 10

jle out_of_block

; some code

out_of_block:

再等價變換回c語言,這裡把這種風格叫做「山寨c**」,實際上就是這樣的:

if( a <= 10 ) goto out_of_block;

// some code

out_of_block:

經過比較,我們可以發現「山寨c**」和「正宗c**」之間的一些區別:

相當於是:不滿足條件就跳過if中的語句塊。

那迴圈呢?咱們把迴圈的c等價**做一次變換,也就是把只含有goto和if的「正宗c**」變換為「山寨c**」的形式:

int sum = 10;

int i = 1;

_start:

if( i > 10 )

sum = sum + i;

i = i + 1;

goto _start;

_end_of_block:

大致看一下流程,再對比源**:

int sum = 0;

int i = 1;

while( i <= 10 )

自己在腦子裡面模擬一遍,是不是就能發現什麼了?這倆貨分明就是乙個東西,執行的順序和過程完全就是一樣的。

到這裡,我們的迴圈結構,全都被拆散成了最基本的結構,這種結構有乙個關鍵的特點:

到這裡,本段就到位了。

前面已經介紹了「如何把乙個迴圈拆解成只有if和goto的結構」,有了這個結構之後,其實要寫出彙編就非常容易了。

繼續看山寨版的迴圈:

int sum = 10;

int i = 1;

_start:

if( i > 10 )

sum = sum + i;

i = i + 1;

goto _start;

_end_of_block:

其實,稍微仔細一點就能發現,把這玩意兒寫成彙編,就是逐行翻譯就完事兒了。動手:

global main

main:

mov eax, 0

mov ebx, 1

_start:

cmp ebx, 10

jg _end_of_block

add eax, ebx

add ebx, 1

jmp _start

_end_of_block:

ret

這裡面其實有乙個套路:

最後,其它語句該幹啥幹啥。

這?竟然?就?用彙編?寫出?迴圈?來了?

嗯,是的。不需要任何乙個新的指令,全都是前面提及過的基本指令,只是套路不一樣了而已。

其實這就是乙個套路,稍微總結一下就能發現,乙個將while迴圈變換為彙編的過程如下:

那while迴圈能夠搞定了,其它型別的呢?do-while迴圈、for迴圈呢?

其實,在c語言中,這三種迴圈之間都是可以相互變換的,也就是說for迴圈可以變形成為while迴圈,while迴圈也可以變成for迴圈。舉個例子:

int i = 1;

int sum = 0;

for(i = 0; i <= 10; i ++)

int sum = 0;

int i = 1;

while( i <= 10 )

上述兩個片段的**,其實就是等價的,僅僅是形式不同。只是有的迴圈思路用for迴圈寫出來好看一些,有的思路用while迴圈寫出來好看一些,別的沒什麼本質區別,經過編譯器一倒騰之後,就更沒有任何區別了。

在彙編中,分支和迴圈結構,都是通過兩類基本的指令實現的:

只是,分支結構的程式中,所有的跳轉目標都是往後,程式一去不復返。而迴圈結構中,程式會根據條件往前跳轉,跳回去執行已經執行過的**,在繞圈圈,就成迴圈了。到彙編層面,本質上,沒啥區別。

好了,組合語言中的流程控制,基本就算完事兒了,實際上,在組合語言中,抓住根本的東西就行了,剩下的就是靠腦子想象了。

組合語言入門 流程控制

流程控制 順序,分支,迴圈 程式計數器pc中儲存當前執行的程式在em中的位置 彙編裡面,用比較 跳轉實現流程控制.1.順序 pc 1 不一定加一,看指令長度 2.分支迴圈,直接賦給pc值,執行指定位址的程式 有時候需要程式有一定的流程控制能力,它不是老老實實按照順序來執行的,中間可能會跳過一些 修改...

Go語言流程控制(六)

go語言的流程控制主要有if for和switch。go語言的if判斷 func main else if score 80 else 需要注意的兩點 1.表示式不可以使用 2.起始花括號必須緊跟表示式後面,不可以另起一行 除此之外,if 判斷寫法還有另一種寫法 func main else if ...

組合語言入門

1.資料傳送類指令 2.算術運算類指令 3.邏輯運算與移位類指令 4.串類指令 5.資料轉移控制類指令 6.處理器控制類指令 注意 本文章中涉及到的暫存器是以 intel 8086作為標準 格式 mov 目的運算元,源運算元 例如 mov ax,bx mov ax,2000h 注意,這一句指令是正確...