我們在上一講中,簡單了解了彙程式設計式大概的樣子。接下來我們來了解一下,彙程式設計式的大小比較操作。是以我們以編寫尋找一堆數中的最大值作為學習的載體。
在編寫程式之前,先要分析我們的目的,在得出解決方案。
目的:在一堆數中找到最大的數
思路:要實作這個目的,首先,我們一定要對資料進行索引,每一次比較,兩個數應該分别占用一個寄存器,得到最大值,是以,我們有一個寄存器一定是存放最大值的。一開始沒有最大值,我們不妨設第一個數為最大值,後面一次索引大小比較。得出最大值。索引中還會用到循環結構。
解決方案——代碼
在代碼之前,先說一下用到的寄存器
%eax – 用來存儲目前資料
%ebx – 用來存儲最大值
%edi – 存儲索引
.section .data
data_items:
.long 3, 14, 15, 9, 26, 53, 58, 97, 93, 2, 38, 4, 36, 0
.section .text
.globl _start
_start:
movl $0, %edi
movl data_items( , %edi, 4), %eax
movl %eax, %ebx
start_loop:
cmpl $0, %eax
je loop_exit
incl %edi
movl data_items( , %edi, 4 ), %eax
cmpl %ebx, %eax
jle start_loop
movl %eax, %ebx
jmp start_loop
loop_exit:
movl $1, %eax
int $0x80
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
把上面的代碼儲存為maximum.s,在編譯連結,運作。正常情況下最大應該是97。
現在來具體解釋代碼:
.section .data 為資料段,前面一節我們提到過。
data_items
.long 3, 14, 15, 9, 26, 53, 58, 97, 93, 2, 38, 4, 36, 0
這是資料段裡面的内容,data_items 是标簽,代表一個位址。在這個位置後面是一堆數字,這些數字的類型是long(長整形,4位元組)。而data_items标簽代表的位址就是這段數字的開頭,在這個例子中,data_items對應的位址下的内容為long類型的數字3。
這個資料項的末尾的0是人為添加,在這裡來作為是否到達末尾的判斷依據。
movl $0, %edi
movl data_items( , %edi, 4), %eax
movl %eax, %ebx
這裡是為循環做好準備,我們要把索引寄存器%edi的值變為0,應為我們要從資料的第一個數字開始擷取資料。
movl data_items( , %edi, 4), %eax 這句是把資料的第一個資料載入到%eax裡面。
這裡的源操作數是data_items( , %edi, 4),目的操作數是%eax,而源操作數比較複雜,這裡涉及到記憶體裡的尋址方式。這一點也是彙編中十分重要的内容。我們下一講具體來講解。這裡想講最基本的。在記憶體中位址引用的通用格式是下面這樣:
位址或偏移(%基址寄存器,%索引寄存器,比例因子)
實際位址 = 位址或偏移 + %基址寄存器 + 比例因子 * %索引寄存器
這裡用到的是索引尋址方式,是利用位址或偏移、%索引寄存器、比例因子來實作。是以出現了上面代碼的表現形式。
在這個例子中data_items為起始位址,後面的各項一一對應,這裡的比例因子是4是因為long類型為4位元組。
movl %eax, %ebx 把第一個數載入到%ebx中作為最大值。
後面我進入了循環,我們用start_loop來标記循環的入口(位置)。
start_loop:
cmpl $0, %eax
je loop_exit
incl %edi
movl data_items( , %edi, 4 ), %eax
cmpl %ebx, %eax
jle start_loop
movl %eax, %ebx
jmp start_loop
一個循環第一考慮的問題就是,循環結束的條件,不然寫出死循環就麻煩了。cmpl —— compare long,比較long類型的大小,結果會記錄在%eflags(狀态寄存器)中je = jump equal 如果值相等,就跳轉。
cmpl $0, %eax
je loop_exit
表示%eax的值為0就跳轉到loop_exit的位置,執行這個位置後面的操作。如果不相等就不跳轉,而是繼續執行後面緊更的操作。
incl %edi
movl data_items( , %edi, 4 ), %eax
incl —— increase long,是以 incl %edi 是讓%edi的值加1,類似于C語言的 i++ 的效果
是以這兩句很在一起的效果就是索引資料,要檢測的數着存放在%eax中。
cmpl %ebx, %eax
jle start_loop
movl %eax, %ebx
jmp start_loop
jle —— jump less equal如果小于等于,跳轉
jmp —— 無條件跳轉
是以這裡就是,如果%eax裡的大值比%ebx中的目前最大值小或相等(注意:比較的方式,到底是那個比那個小),這跳轉到start_loop位置,執行這個位置後面的代碼,也就是跳過後面操作,回到循環的開頭。如果不成立,執行下面步驟,就是把%eax裡面的值載入到%ebx作為新的最大值。跳會循環開始處。
movl $1, %eax
int $0x80
對于這個程式,這麼解釋,實在是太累了,最為教程的前幾期,會講的詳細,每一步都講,到後面基本之講重點。
最後,最好在回顧一遍,在寫一遍,你可以對其進行改進,這一次寫,可不是對着代碼敲下來,而是自己寫。
附加内容:
資料類型
- .byte —— 位元組類型,隻占用一個位元組
- .int —— 整型,占用2個位元組
- .long —— 長整型,占用4個位元組
- .ascii —— ascii碼類型字元,一個字元占1個位元組
大小判斷
- je = jump equal 如果值相等,就跳轉。
- jg = jump greater 如果第二個值大于第一個值,跳轉
- jge = jump greater equal 如果第二個值大于等于第一個值,跳轉
- jl = jump less equal如果第二個值小于第一個值,跳轉
- jle = jump less equal如果第二個值小于等于第一個值,跳轉
- jmp 無條件跳轉
人就像是被蒙着眼推磨的驢子,生活就像一條鞭子;當鞭子抽到你背上時,你就隻能一直往前走,雖然連你也不知道要走到什麼時候為止,便一直這麼堅持着。