目錄編程
已經很久沒寫點東西了,國慶節就一直想弄個我的網站,這段時間一直在弄那個,雖然有現成的框架(Hexo),可是總想弄出本身的效果來,可是最後仍是有些差強人意,只好打翻了有重來(強迫症表示難受),也懶得弄那麼多了。好在最近差很少事情也理順了,今天強迫本身靜下來寫了點東西。框架
今天看了下彙編中的[BX]和Loop指令,Loop指令容易知道,一看就是用來作循環的指令,那麼[BX]又是什麼呢?oop
首先咱們知道,要完整的描述一個內存單元,須要兩種信息:網站
對於第一個——【內存單元的地址】,咱們知道,用[addr]能夠表示一個內存單元,其中addr表示這個內存單元的偏移地址,段地址默認在DS寄存器中。而單元的長度(類型)則能夠由指令中的其餘操做對象指出(如寄存器),就像下面這樣:code
mov ax, [0]
那麼,在這裏[BX]也表示一個內存單元,其偏移地址存於BX寄存器中,段地址默認在DS寄存器中。也把BX寄存器叫作基址寄存器。對象
爲了方便後面的敘述,這裏做兩個約定,固然也是跟着書上的來啦,哈哈,不過我發現不少書上也都默認有這個敘述方法。內存
用描述性符號「( )」表示一個寄存器或一個內存單元中的內容,如:it
(ax) 表示寄存器AX中的內容,(al) 表示寄存器AL中的內容。 (addr) 表示物理地址爲addr的內存單元中的內容。
所以"( )"中的元素類型有3種:asm
其所表示的數據類型有:class
具體是那種類型則由寄存器名或具體的運算符決定。
用idata表示一個常量。
如用mov ax, [idata]
表明mov ax, [1]
、mov ax, [2]
等。
如用mov bx, idata
表明mov bx, 1
、mov bx, 2
等。
咱們對[BX]的使用有以下用法:
mov ax, [bx] ; bx中存放的數據做爲偏移地址,段地址默認在ds中,(ax) = ((ds) * 16 + (bx)) mov [bx], ax ; bx中存放的數據做爲偏移地址,段地址默認在ds中,((ds) * 16 + (bx)) = (ax)
Loop指令用於實現循環功能,循環次數存於CX寄存器中 。
【格式】loop 標號
示例:
mov cx, 5 ; 設置循環次數 s: ; 標號 add ax, ax ; 循環執行的程序段 loop s ; Loop指令
Loop指令一般用於執行某些須要重複運行的指令,好比操做某一塊連續的內存地址塊。一般把循環次數存於CX寄存器中,CPU經過判斷CX裏面的值是否爲零來決定是否執行循環。CPU執行Loop指令的描述以下:
1. (CX) = (CX) -1 2. (CX)不爲零,轉去標號處執行,反之不執行循環,向下執行指令
這裏的標號"s"並非固定的,你也能夠指定其餘的標號。在這裏標號其實是標識了一個地址,在該地址處存在着咱們的程序指令(如上面的add ax, ax),在執行循環的時候,若CX的值不爲零,則"Loop 標號"指令將IP的值設置爲標號所標識的地址,CPU就將執行IP所指向的指令。
咱們能夠獲得這樣一個Loop指令的簡單框架:
mov cx, 循環次數 label: 須要循環執行的程序段 loop label
【注意】書上的一個實例程序中提到在彙編程序中的數據表示問題,咱們知道,在彙編中,數據多以16進製表示,而16進制中有 'A~F' 6個字母,可是在彙編源程序中,數據的書寫不能以字母開頭,如「9876H」能夠直接書寫爲「9876H」,可是「A000H」不能書寫成「A000H」,而需寫爲「0A000H」(以0開頭)。
在實際編程中可能會遇到要處理某一段地址連續的內存單元中的數據,一般可用循環來解決這類問題。在這樣的循環過程當中,須要一個變量來保存內存單元的偏移地址,這時候「基址寄存器——BX」就起做用了。
【注:如下內容來自王爽的《彙編語言》(第三版)】
考慮這麼一個問題,咱們要計算 ffff:0~ffff:b 單元中的數據的和,要求將結果存儲在dx寄存器中。
咱們首先分析一下:
ffff:0~ffff:b 內存單元中的數據是字節型的數據,範圍在0~255之間,12個這樣的數據相加的結果不會大於65535,是能夠存儲在dx寄存器中的。
這是比不可能的,爲何?由於數據類型不匹配,dx是16位寄存器,而 ffff:0~ffff:b 中的數據是8位的。
看第一條分析,12個8字節的數據相加是有可能超過255的,而咱們的dl是8位寄存器,那麼答案很明顯了。不能!
這裏有兩個問題,類型的匹配和結果的不超界,咱們能夠考慮用一個16位的寄存器來作中介。將內存單元中的8位數據賦值到一個16位寄存器ax中,再將ax中的數據加到dx上,從而使兩個運算對象類型匹配而且結果不會超界。
考慮完以上問題,很明顯,若是是在高級語言中,這是一個很容易作的問題,一個循環就能夠實現,那麼在彙編中,咱們也能夠用循環來實現這個操做。咱們能夠把BX用做存儲內存單元偏移地址的變量,在每次循環的時候改變BX中的值,從而實現把 ffff:0~ffff:b 12個內存單元中的數據相加。
實現以下:
assume cs:code code segment start: ;程序入口 mov ax, 0ffffh mov ds, ax mov bx, 0 ;初始化ds:bx指向ffff:0 mov dx, 0 ;初始化累加寄存器dx,(dx)=0 mov cx, 12 s: mov al, [bx] mov ah, 0 add dx, ax inc bx ;使ds:bx指向下一個內存單元 loop s mov ax, 4c00h int 21h code ends end start ;程序結束
在指令「mov ax, [bx]」中,內存單元的偏移地址由bx指出,而段地址則默認存儲在ds中。可是咱們能夠在訪問內存單元的指令中顯示給出內存單元的段地址所在的段寄存器,如:
mov ax, ds:[bx] mov ax, cs:[bx] mov ax, ss:[bx] mov ax, es:[bx] mov ax, ss:[0] mov ax, cs:[0]
這些出如今訪問內存單元的指令中,用於顯示地指明內存單元的段地址的「ds:」 「cs:」 「es:」 「ss:」,在彙編語言中稱爲段前綴。
考慮一個問題,將內存單元 ffff:0~ffff:b 單元中的數據複製到 0:200~0:20b 單元中。
分析:
實現以下:
assume cs:code code segment mov ax, 0ffffh mov ds, ax ;(ds)=0ffffh mov ax, 0020h mov es, ax ;(es)=0020h mov bx, 0 ;此時ds:bx指向ffff:0,es:dx指向0020:0 mov cx, 12 s: mov dl, [bx] ;段地址默認在ds中 mov es:[bx], dl ;段前綴指明內存段 inc bx loop s mov ax, 4c00h int 21h code ends end