天天看點

Linux彙編教程03:大小比較操作

我們在上一講中,簡單了解了彙程式設計式大概的樣子。接下來我們來了解一下,彙程式設計式的大小比較操作。是以我們以編寫尋找一堆數中的最大值作為學習的載體。

在編寫程式之前,先要分析我們的目的,在得出解決方案。

目的:在一堆數中找到最大的數

思路:要實作這個目的,首先,我們一定要對資料進行索引,每一次比較,兩個數應該分别占用一個寄存器,得到最大值,是以,我們有一個寄存器一定是存放最大值的。一開始沒有最大值,我們不妨設第一個數為最大值,後面一次索引大小比較。得出最大值。索引中還會用到循環結構。

解決方案——代碼

在代碼之前,先說一下用到的寄存器

%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。

Linux彙編教程03:大小比較操作

現在來具體解釋代碼:

.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  無條件跳轉

人就像是被蒙着眼推磨的驢子,生活就像一條鞭子;當鞭子抽到你背上時,你就隻能一直往前走,雖然連你也不知道要走到什麼時候為止,便一直這麼堅持着。