1. 程式人生 > >組合語言(王爽第三版)實驗4

組合語言(王爽第三版)實驗4

1.程式設計:向記憶體0:200H~0:23fH依次傳送資料0~633FH

程式分析:

1】記憶體0:200H~0:23fH空間與0020:0-0020:3f記憶體空間是一樣的,(這個不會?ohMy God!,實體地址是唯一的,但邏輯地址組合是多種的。)

2】因為偏移地址是連續記憶體單元;我們可以把偏移地址做下文章。bx暫存器儲存偏移地址(通過偏移地址的間接訪問記憶體單元,這主要是寫入的記憶體單元)。dx暫存器作為儲存中間變數的容器(源資料,常量0-63)來向記憶體寫入。

 彙編程式碼如下:

assume cs:code

code segment

    mov ax,0020H

    mov ds,ax   ;記憶體單元的段地址寫入ds

暫存器

    mov bx,0    ;bx暫存器存放偏移地址,初始化為0

    mov dx,0    ;dx暫存器儲存常量數值0~63

    mov cx,40H  ;這裡40H==64cx暫存器存放迴圈次數。也可以為64

s:  mov [bx],dx ;[bx]記憶體單元寫入dx

    inc bx  ;累加bx

    inc dx  ;累加dx

    loop s

    mov ax,4c00H

    int 21H

code ends

end

2. 向記憶體0:200H~0:23fH依次傳送資料0~633FH),9條命令的程式的簡化版本(不包括虛擬碼):

程式分析:

1】記憶體0:200H~0:23fH空間與0020:0-0020:3f

記憶體空間是一樣的,(這個不會?ohMy God!,實體地址是唯一的,但邏輯地址組合是多種的。)為什麼這樣?資料0-6364個連續的數字,0-3fH也是連續的64個編號。我們可以使用一個bx變數就把偏移地址和數字的遞增都搞定了!

修改後的彙編程式碼如下:

assume cs:code

code segment

    mov ax,0020H

    mov ds,ax   ;ds指向0020記憶體段

    mov bx,0    ;bx暫存器存放偏移地址,初始化為0,也當做源資料:常量數值

    mov cx,64   ;迴圈次數64

s:  mov [bx],bx ; [bx]記憶體單元寫入bx數值

    inc bx

    loop s

    mov ax,4c00h

    int 21H

code ends

end

實驗體會:

1. bx暫存器一般用作偏移地址的儲存,[bx]也就代表了段地址與[bx]組合後指向的記憶體單元。 為什麼這樣,還有一個原因就是在源程式中[xxxx]masm編譯器中當做了常量xxxx,[bx]則沒有這個問題,編譯器當做是一個記憶體地址段的偏移地址。

2.cx暫存器在迴圈語句中,常作為計數器使用,loop迴圈語句把cx暫存器中的值作為判斷是否迴圈的依據。

       CX暫存器在debug除錯一個可執行程式時,CX的初始值為該程式的位元組尺寸大小。

3.ds暫存器存放的是指向的記憶體單元的段地址。

4.debug模式下,注意源程式中loop s語句的體現,直接轉移到了一個地址(偏移地址)了。

5.結束debug程式,鍵入q,退回到dos或命令提示符狀態。

6.debug狀態下,如果想要直接執行的到某個語句,可使用g命令,例如:

       g  XXXX(偏移地址) 在此之前的命令都執行了。

7.在彙編源程式中,資料不能以字母開頭,前面可以加0,例如:0ff02H

8.debug下除錯程式,遇到int 21H命令,鍵入p命令結束程式。

9.使用p命令可以結束loop的迴圈(當你遇到了loop語句的時候)。

10.在寫彙編程式時,十進位制和十六進位制(用hH標註)可以混用。編譯器自動給你轉換了。

程式執行後結果:

-d ds:0

0020:0000  00 01 02 03 04 05 06 07-08 09 0A 0B 0C 0D 0E 0F   ................

0020:0010  10 11 12 13 14 15 16 17-18 19 1A 1B 1C 1D 1E 1F   ................

0020:0020  20 21 22 23 24 25 26 27-28 29 2A 2B 2C 2D 2E 2F    !"#$%&'()*+,-./

0020:0030  30 31 32 33 34 35 36 37-38 39 3A 3B 3C 3D 3E 3F   0123456789:;<=>?

3.下面程式的功能是將mov ax,4c00H之前的指令複製到記憶體0:200處,補全程式,上機除錯,跟蹤執行結果:

程式分析:

1】使用debug除錯一個EXE檔案時候,使用r命令檢視暫存器狀態,其中cx暫存器的值(初始值)就是該程式程式碼的大小(按照位元組數)。我們可以通過執行debug程式來除錯生成的EXE檔案,前提你先將CX暫存器賦個值。

 側面驗證CX暫存器的另一個作用。

2cs段暫存器中儲存的是指向程式程式碼段的段地址。此實驗是將程式的程式碼(按位元組)複製,故將cs暫存器中的指向程式碼的段地址賦值給ax,再通過ax暫存器賦值給ds段暫存器。(為什麼不能支援從段暫存器cs直接賦值給段暫存器ds呢?回憶下,在8086CPU中,dssscses四個段暫存器存放的都是段地址,在CPU和我們來看。其他的暫存器一般存放的都是資料。

 4個段暫存器支援從其他暫存器中賦值,但不允許立即數直接賦值給段暫存器。)

3[bx]作為偏移地址為bx的記憶體單元,它支援的段地址預設是儲存在ds段暫存器中的。 本例中ds[bx]指向的是儲存程式碼段的記憶體單元(源記憶體段)。由於ds被佔用了,故被寫入的記憶體單元的段地址就沒有儲存的段暫存器了,es暫存器上場了,es儲存了地址為0020H的段地址(目標記憶體段),那麼同樣使用[bx]偏移地址的話,必須明確的指出它的字首,故es[bx]就指向了記憶體是0200H的記憶體單元地址段。

實驗步驟如下:

1)首先使用debug除錯該程式:假如這個可執行程式(經編譯、連線無誤後的)為test5.exe

debug  test5.exe 

2)使用r命令顯示暫存器狀態,顯示整個程式程式碼所佔位元組數。

-r

AX=0000  BX=0000  CX=001C  DX=0000  SP=0000  BP=0000  SI=0000  DI=0000

DS=0B55  ES=0B55  SS=0B65  CS=0B65  IP=0000   NV UP EI PL NZ NA PO NC

0B65:0000 8CC8          MOV     AX,CS

這裡我們發現CX= 001CH

3)使用u命令顯示彙編指令,求出需要複製的機器碼位元組數。

-u cs:0000

0B65:0000 8CC8          MOV     AX,CS

0B65:0002 8ED8          MOV     DS,AX

0B65:0004 B82000        MOV     AX,0020

0B65:0007 8EC0          MOV     ES,AX

0B65:0009 BB0000        MOV     BX,0000

0B65:000C B90300        MOV     CX,0003

0B65:000F 8A07          MOV     AL,[BX]

0B65:0011 26            ES:

0B65:0012 8807          MOV     [BX],AL

0B65:0014 43            INC     BX

0B65:0015 E2F8          LOOP    000F

0B65:0017 B8004C        MOV     AX,4C00

0B65:001A CD21          INT     21

 我們發現mov ax,4cooH/int 21H它們共佔用了5個位元組。所以在本實驗中我們需要複製的程式碼位元組數是001CH-0005H=0017H==23個位元組,故cx計數暫存器賦值為2317H

4)完整的彙編程式碼如下:

assume cs:code

code segment

    mov ax,cs       ;cs段地址賦值給ax

    mov ds,ax       ;cs暫存器中的值初始化ds段暫存器,

    mov ax,0020H

    mov es,ax       ;es指向0020H記憶體段

     mov bx,0        ;偏移地址暫存器清零

    mov cx,17H      ;此處是迴圈次數:程式機器碼的位元組數,儲存在CX

s:  mov al,[bx]     ;[bx]按照位元組單元傳送給al

    mov es:[bx],al  ;複製到es段記憶體中

    inc bx

    loop s

    mov ax,4c00H

    int 21H

code ends

end

實驗結果測試:

-d 20:0

0020:0000  8C C8 8E D8 B8 20 00 8E-C0 BB 00 00 B9 17 00 8A   ..... ..........

0020:0010  07 26 88 07 43 E2 F8 00-00 00 00 00 00 00 00 00   .&..C...........

……

我們發現偏移地址從0000H~0017H儲存了程式的執行程式碼。與程式執行程式碼儲存的記憶體單元比較,我們發現一樣的。

-d cs:0

0B65:0000  8C C8 8E D8 B8 20 00 8E-C0 BB 00 00 B9 17 00 8A   ..... ..........

0B65:0010  07 26 88 07 43 E2 F8 B8-00 4C CD 21 FF 06 48 91   .&..C....L.!..H.