匯編語言(王爽第三版)實驗7 尋址方式在結構化數據訪問中的應用


實驗7   尋址方式在結構化數據訪問中的應用

 

問題提出:Power idea公司的基本情況如下:

       見書中數據列表:

下面格式已經定義好了這些數據:

assume cs:code 

data segment  

    db '1975','1976','1977','1978','1979','1980','1981','1982','1983'  

    db '1984','1985','1986','1987','1988','1989','1990','1991','1992'  

    db '1993','1994','1995' 

    ;以上是表示21年的21個字符串

    dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514  

    dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000  

    ;以上是表示21年 公司總收入的21個dword型數據

    dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226  

    dw 11542,14430,15257,17800

    ;以上是表示21公司雇員人數的21個Word型數據。

data ends  

table segment  

    db 21 dup ('year summ ne ?? ')  

table ends

code segment

start:

        ???????

        mov ax,4c00H

        int 21H

code ends

end start

實驗要求:將data段中的數據,按照書中的格式寫入到table段中,並計算21年中的人均收入(取整),結果也按照下面的格式保存在table段中。

實驗分析:

       此實驗定義並初始化了2個數據段(注意段的表示方法),從源內存段data中將數據讀取出來后,按照一定的格式要求(有的數據需要處理)寫入到目的內存段table中。

實驗目的:

       1. 在一個數據段中定義不同的數據類型(字符、字符串和數值)的方式,並考察他們在內存中的存儲情況。

       2. 掌握dup的用法。

       3. 考察我們對同一個數據段的內存單元,不同的尋址方式。

       4. 掌握DIV除法的基本應用。

       5. 怎樣結構化的在內存中存儲數據。

       6. 熟練掌握我們以前所學習的寄存器的用法,並歸納總結。

程序分析:

       考慮到此程序使用了2個數據段,並且我們同時要使用這2個數據段,我們除了使用通用的數據段寄存器DS外,另外使用ES寄存器來進行另外一個數據段的尋址。這樣我們指定data段的段地址存儲在DS中,table段的段地址存儲在ES中。

       在data段中,我們觀察並考慮怎樣使用靈活多變的尋址方式來訪問內存(這時候我們在腦海中應該有對於data段數據的內存存儲有映像了)。通俗講就是怎樣在內存中尋址。

       1. 程序定義並初始化了data段,考慮程序中一共使用了3中數據類型,單字節類型(一個字節)、Word字類型(2個字節)、DW雙字類型(4個字節)。它們在內存單元中所占用的連續空間是不同的。(問題提出:為什么要使用不同的數據類型?這個在C語言及其他高級語言中同樣適用。不同的數據類型匹配不同的數據,做到合理安排數據在內存中存儲,不浪費空間,提高運行速度。)

       因為在data段中,這些初始化的數據在內存中是連續存儲的。(這時如果我們對於他們在內存中的存儲有疑問,可以使用debug來查看下它們具體的存儲情況,這樣比較直觀的體驗下)。例如:部分存儲情況(怎么來的?不寫其他代碼,編譯連接debug后得出的):

-d ds:00

0B65:0000  31 39 37 35 31 39 37 36-31 39 37 37 31 39 37 38   1975197619771978

0B65:0010  31 39 37 39 31 39 38 30-31 39 38 31 31 39 38 32   1979198019811982

0B65:0020  31 39 38 33 31 39 38 34-31 39 38 35 31 39 38 36   1983198419851986

0B65:0030  31 39 38 37 31 39 38 38-31 39 38 39 31 39 39 30   1987198819891990

0B65:0040  31 39 39 31 31 39 39 32-31 39 39 33 31 39 39 34   1991199219931994

0B65:0050  31 39 39 35 10 00 00 00-16 00 00 00 7E 01 00 00   1995........~...

0B65:0060  4C 05 00 00 56 09 00 00-40 1F 00 00 80 3E 00 00   L...V...@....>..

0B65:0070  A6 5F 00 00 91 C3 00 00-C7 7C 01 00 81 24 02 00   ._.......|...$..

-d

0B65:0080  8A 03 03 00 7C 47 05 00-EB 03 09 00 CA 42 0C 00   ....|G.......B..

0B65:0090  18 0D 12 00 38 1F 1C 00-58 19 2A 00 28 44 39 00   ....8...X.*.(D9.

0B65:00A0  28 F0 46 00 68 97 5A 00-03 00 07 00 09 00 0D 00   (.F.h.Z.........

0B65:00B0  1C 00 26 00 82 00 DC 00-DC 01 0A 03 E9 03 A2 05   ..&.............

0B65:00C0  D2 08 E9 0A C5 0F 03 16-22 20 16 2D 5E 38 99 3B   ........" .-^8.;

0B65:00D0  88 45 00 00 00 00 00 00-00 00 00 00 00 00 00 00   .E..............

0B65:00E0  79 65 61 72 20 73 75 6D-6D 20 6E 65 20 3F 3F 20   year summ ne ??

0B65:00F0  79 65 61 72 20 73 75 6D-6D 20 6E 65 20 3F 3F 20   year summ ne ??

      

data數據段:

       我們發現:.

       年份:在0b65:0000~0053H中存儲的是21個字符串(沒0結尾的)。(21個字符串它所占內存空間為21*4=84Bytes);黑色表示

       收入:在0b65:054~00A7H中存儲的是21個dword數據(21個dword型數據,它所占內存空間為:21*4=84Bytes);(??看下開始,它們都是4字節的。第一個數存儲的是10H,就是16,剩下3個高位單元都是00H,對了,它就代表是16;最后,68 97 5A 00 實際它是005A9768H=593700)紅色表示

       雇員人數:00A8~00D1中存儲的是21個word型數據,它所占內存空間為:21*2 = 42Bytes;綠色表示。

       為什么后面的14個字節都是00H?是否浪費了?因為程序又重新定義並初始化了一個數據段用來存放year summ ne ??了。那么14個字節基本就是浪費了。

       這時候我們考慮怎樣來表示data段中的內存(能夠表示了,那么就代表能夠尋址了)

table數據段:

       0B65:00E0開始是table數據段的內存地址了,如果偏移地址是0000H,那么它的段地址就是:0B73。   0B65:00E0H==0B73:0000H

       定義時使用了db語句,定義的字符串正好是16個字節,在debug中就是一行。重復21行,也就是在table數據段有21行的'year summ ne ?? '(體會這樣的好處,省的在table數據段重復定義21次了,一個dup語句就搞定了。)

       強烈提示:這個是在debug中,為了顯示方便,每行內存都是16個字節,但真正的內存是單列存儲的,是沒有行這個概念的。

對源數據的讀取:    

       對於21個字符串的尋址:

       考慮到這個程序就是整個復制字符串,而不是修改它的內容,所以我們的尋址方式應該簡化。考慮該字符串都是占用4個字節,那么我們使用ax寄存器操作2次就可以把一個字符串復制了;我們采用[bx+idata]方式尋址就可以了。其中idata(0,2)。一個字符串:例如1975占用4個字節的內存,其中[bx+0]=3139H,[bx+2]=3735H.

       bx的范圍:0~83

       對於21個dword型數據的尋址:        

       同樣道理,通過寄存器傳送2個字就可以了。

       注意此時idata有變化了,idata初始值變成了84了(84,86)

       對於21個word型數據的尋址:

       同樣道理,一個寄存器就搞定了。每次就一個字(8086CPU普通寄存器就是一個字),

       注意此時idata又有變化了,idata的初始值變成了168(0+84+84=168)。

對目標內存的寫入:

       由於DS寄存器被使用了。我們不得不使用ES寄存器來存儲table數據段的基地址(段地址)。(ES)= (table)

       由於bx變址寄存器被使用了(ax不能用、cx作為計數器、dx呢做除法去了。呵呵),我們再使用其他的個變址寄存器之一就行了。

       我們可以使用si寄存器。那么通過es:si就可以對目標內存進行尋址了。

       還有一個問題就是對於雇員數的地址,它的規律是每次+2的偏移,需要再搞個寄存器來進行變址,我這用了di。(因為在前面2個數據都是4個字節的,偏移量+4可以,但雇員數應該是+2)

       對於空格的處理:由於空格的ASCII碼是:32(20H)。占用一個字節。這時候我們要注意傳送的是一個字節,不是一個字,故應該使用的是8位寄存器,例如:al。

       關於結構化內存的寫入:我們發現實驗中要求我們在一行(16個字節中)正好寫入這些數據(包括空格),那么我們注意空格的寫入會導致在變址寄存器變量的有規律變化,在debug中就是按照一行的內存顯示,其實他們的規律變化都是基於16個字節。

       表格一行的組成如下(含偏移地址si=0000H,段地址在ES中,這個可以畫圖說明):

       年份(4個字節):(si)= 0000H~0003H   (si +0   is +2)

       空格:               (si)= 0004H                    (is+4)

       收入(4個字節):(si)= 0005H~0008H    (si +5   is + 7)

       空格                     (si)= 0009H          (si +9)

       雇員數(2個字節)(si)= 000aH~000bH        (si +10)

       空格:                  (si)= 000cH                   (si +12)

       人均收入(2個字節)(si)= 000dH~000eH            (si + 13)

       空格                            (si)= 000fH              (si + 15)

 

關於除法在此題目中的應用:

       我們發現:被除數(總收入)是32位的,除數(雇員數)是16位的,那么在做除法時它們應該怎樣存儲?

       被除數:低16位的存儲在ax中,高16位的存儲在dx中;那么(ax)= (bx+84);

(dx) = (bx+86)。相應代碼為:

       mov ax,[bx+84]

       mov dx,[bx+86]

       除數:我們將除數存儲在bp寄存器中吧,因為考慮以后有寄存器的沖突。

       mov bp,[di+168]

       div bp

       mov es:[si+13],ax         

       除法的應用,我們有個小專題專門講解下。

最終的代碼如下:    

assume ds:data, es:table, cs:code 

 

data segment  

    db '1975','1976','1977','1978','1979','1980','1981','1982','1983'  

    db '1984','1985','1986','1987','1988','1989','1990','1991','1992'  

    db '1993','1994','1995' 

  ;以上是表示21年的21個字符串

    dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514  

    dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000  

  ;以上是表示21年 公司總收入的21個dword型數據

    dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226  

    dw 11542,14430,15257,17800

  ;以上是表示21公司雇員人數的21個Word型數據。

data ends  

 

table segment  

    db 21 dup ('year summ ne ?? ')  

table ends

 

code segment

start:

      ;初始化2個數據段,將ds指向data,es指向table

      mov ax,data

      mov ds,ax

      mov ax,table

      mov es,ax

      ;初始化偏址寄存器變量

      mov bx,0

      mov si,0

      mov di,0

      ;共21行,循環21次,初始化計數器

      mov cx,21  

  s: 

      ;寫入年份

      mov ax,0[bx]            ;如看着別扭,改成mov ax, [bx+0] 

      mov es:0[si],ax

      mov ax,2[bx]

      mov es:2[si],ax

      ;寫入空格

      mov al,20H

      mov es:4[si],al

      ;寫入收入

      mov ax,84[bx]

      mov es:5[si],ax

      mov ax,86[bx]

      mov es:7[si],ax

      ;寫入空格

      mov al,20H

      mov es:9[si],al

      ;雇員數

      mov ax,168[di]

      mov es:10[si],ax

      ;寫入空格

      mov al,20H

      mov es:12[si],al

      ;人均收入,高16位送入dx,低16位送入ax

      mov ax,[bx+84]

      mov dx,[bx+86]

      ;用個bp變量存儲除數,為以后實驗考慮

      mov bp,[di+168]

      div bp                  ;16位除法指令

      mov es:13[si],ax        ;將商的結果(ax)寫入table段中

      ;寫入空格

      mov al,20H

      mov es:15[si],al

      ;bx、si、di變量的遞增

      add bx,4                ;年份和總收入都是雙字單元,故bx的遞增量是4

      add si,16               ;table中每行是16個字節,偏移量為16

      add di,2                ;人數是字單元,故di的遞增量是2

      loop s

     

      mov ax,4c00H

      int 21H

code ends

end start

實驗結果:編譯、連接后,在debug中,查看table段內存:

-d es:0

0B73:0000  31 39 37 35 20 10 00 00-00 20 03 00 20 05 00 20   1975 .... .. ..

0B73:0010  31 39 37 36 20 16 00 00-00 20 07 00 20 03 00 20   1976 .... .. ..

0B73:0020  31 39 37 37 20 7E 01 00-00 20 09 00 20 2A 00 20   1977 ~... .. *.

0B73:0030  31 39 37 38 20 4C 05 00-00 20 0D 00 20 68 00 20   1978 L... .. h.

0B73:0040  31 39 37 39 20 56 09 00-00 20 1C 00 20 55 00 20   1979 V... .. U.

0B73:0050  31 39 38 30 20 40 1F 00-00 20 26 00 20 D2 00 20   1980 @... &. ..

0B73:0060  31 39 38 31 20 80 3E 00-00 20 82 00 20 7B 00 20   1981 .>.. .. {.

0B73:0070  31 39 38 32 20 A6 5F 00-00 20 DC 00 20 6F 00 20   1982 ._.. .. o.

……

……

程序總結:

       1)這個實驗是將空格作為每一個數據的結尾,對於字符串來說,結尾應該是0。便於將來判斷是否為字符串。

       2)可以把table段中的一行看做是結構體。

       3)加深數據在內存中存儲的形式,並在腦海中抽象出來。  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM