例 18.2. 求一組數的最大值的彙編程序
#PURPOSE: This program finds the maximum number of a # set of data items. # #VARIABLES: The registers have the following uses: # # %edi - Holds the index of the data item being examined # %ebx - Largest data item found # %eax - Current data item # # The following memory locations are used: # # data_items - contains the item data. A 0 is used # to terminate the data # .section .data data_items: #These are the data items .long 3,67,34,222,45,75,54,34,44,33,22,11,66,0 .section .text .globl _start _start: movl $0, %edi # move 0 into the index register movl data_items(,%edi,4), %eax # load the first byte of data movl %eax, %ebx # since this is the first item, %eax is # the biggest start_loop: # start loop cmpl $0, %eax # check to see if we've hit the end je loop_exit incl %edi # load next value movl data_items(,%edi,4), %eax cmpl %ebx, %eax # compare values jle start_loop # jump to loop beginning if the new # one isn't bigger movl %eax, %ebx # move the value as the largest jmp start_loop # jump to loop beginning loop_exit: # %ebx is the status code for the _exit system call # and it already has the maximum number movl $1, %eax #1 is the _exit() syscall int $0x80
彙編、連結、運行:
$ as max.s -o max.o $ ld max.o -o max $ ./max $ echo $?
這個程序在一組數中找到一個最大的數,並把它作為程序的退出狀態。這組數在.data
段給出:
data_items: .long 3,67,34,222,45,75,54,34,44,33,22,11,66,0
.long
指示聲明一組數,每個數占32位,相當於C語言中的數組。這個數組開頭定義了一個符號data_items
,彙編器會把數組的首地址作為data_items
符號所代表的地址,data_items
類似於C語言中的數組名。data_items
這個標號沒有用.globl
聲明,因為它只在這個彙編程序內部使用,連結器不需要用到這個名字。除了.long
之外,常用的數據聲明還有:
.byte
,也是聲明一組數,每個數占8位
.ascii
,例如.ascii "Hello world"
,聲明11個數,取值為相應字元的ASCII碼。注意,和C語言不同,這樣聲明的字元串末尾是沒有'\0'
字元的,如果需要以'\0'
結尾可以聲明為.ascii "Hello world\0"
。
data_items
數組的最後一個數是0,我們在一個循環中依次比較每個數,碰到0的時候讓循環終止。在這個循環中:
edi
寄存器保存數組中的當前位置,每次比較完一個數就把edi
的值加1,指向數組中的下一個數。
ebx
寄存器保存到目前為止找到的最大值,如果發現有更大的數就更新ebx
的值。
eax
寄存器保存當前要比較的數,每次更新edi
之後,就把下一個數讀到eax
中。
_start: movl $0, %edi
初始化edi
,指向數組的第0個元素。
movl data_items(,%edi,4), %eax
這條指令把數組的第0個元素傳送到eax
寄存器中。data_items
是數組的首地址,edi
的值是數組的下標,4表示數組的每個元素占4位元組,那麼數組中第edi
個元素的地址應該是data_items + edi * 4
,寫在指令中就是data_items(,%edi,4)
,這種地址表示方式在下一節還會詳細解釋。
movl %eax, %ebx
ebx
的初始值也是數組的第0個元素。下面我們進入一個循環,循環的開頭定義一個符號start_loop
,循環的末尾之後定義一個符號loop_exit
。
start_loop: cmpl $0, %eax je loop_exit
比較eax
的值是不是0,如果是0就說明到達數組末尾了,就要跳出循環。cmpl
指令將兩個操作數相減,但計算結果並不保存,只是根據計算結果改變eflags
寄存器中的標誌位。如果兩個操作數相等,則計算結果為0,eflags
中的ZF位置1。je
是一個條件跳轉指令,它檢查eflags
中的ZF位,ZF位為1則發生跳轉,ZF位為0則不跳轉,繼續執行下一條指令。可見比較指令和條件跳轉指令是配合使用的,前者改變標誌位,後者根據標誌位決定是否跳轉。je
可以理解成“jump if equal”,如果參與比較的兩數相等則跳轉。
incl %edi movl data_items(,%edi,4), %eax
將edi
的值加1,把數組中的下一個數傳送到eax
寄存器中。
cmpl %ebx, %eax jle start_loop
把當前數組元素eax
和目前為止找到的最大值ebx
做比較,如果前者小於等於後者,則最大值沒有變,跳轉到循環開頭比較下一個數,否則繼續執行下一條指令。jle
表示“jump if less than or equal”。
movl %eax, %ebx jmp start_loop
更新了最大值ebx
然後跳轉到循環開頭比較下一個數。jmp
是一個無條件跳轉指令,什麼條件也不判斷,直接跳轉。loop_exit
符號後面的指令調_exit
系統調用退出程序。