3. 第二個彙編程序

例 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之外,常用的數據聲明還有:

data_items數組的最後一個數是0,我們在一個循環中依次比較每個數,碰到0的時候讓循環終止。在這個循環中:

_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系統調用退出程序。