王爽《組合語言》第八章實驗七 題目分析解答

來源:互聯網
上載者:User

 

王爽老師的《組合語言》是很好的一本彙編書,裡面用通俗的例子講清楚了很多讓彙編初學者一直困惑的痛點。比如寄存器分段定址、各種寄存器的作用等等。

第八章是這本書的一個總結性的章節,後面也給出了一道比較綜合的題目,完成這道題是對之前學習的檢驗,所以要繼續往下學習,這道題是必須完成的。

經過半天時間的編程,本人也完成了這道綜合的題目,在寫代碼的過程中,也搜尋過一些參考的代碼,但大多數網上的資料只是給出了代碼,沒有分析。所以我這裡順便給出一個分析的思路,

是對自己思路的總結,也希望能幫到其他一些要完成這道題目的朋友。下面就是完成這道題目的分析過程。

 

題目的要求:將一段記憶體裡連續的資料,複製到另一段結構化了的記憶體裡。具體的可以參看原書。

分析:
 首先拿到了這道題目,就分析一下這兩塊資料地址的變化規律,畢竟我們的痛點在於如何定址嘛,這些地址的變化規律看一下,可以知道,第一塊年資料地址之間相隔4,第二塊收入資料地址之間相隔也是4,
第三塊僱員資料地址之間相隔2,第一塊資料和第二塊資料地址之間相隔4*21=84=54H(因為一個年資料佔了4個位元組),第二塊資料和第三塊資料地址之間也是相隔84=54h(dword)。

如所示(懶得用工具作圖了,直接用筆畫了拍下來,多多包涵。。。):

 

 

圖:未經處理資料地址規律

 

 然後分析一下目的資料地址的規律,因為這塊地址已經被格式化了,每一行佔16個位元組,然後有21行,行與行之間相差16,每一行的內容按位元組數填就是了,很簡單。如:

 

圖:目的資料地址規律

 

 有了上面的分析,我們來想想這塊代碼應該怎麼寫,一個最簡單的辦法是,一個個位元組填,不用變址來尋,可行嗎?可行,但這樣你可能要寫21段差不多的代碼。
 
 看來王爽老師設計的這個題目,還是需要用到變址定址,偷懶不得啊。。。

 

 下面就想第二個辦法,因為這些地址的變化都是有規律的,用變址也不難,再想想我們有什麼資源,我們有幾個變址寄存器:bx、bp、si、di。
 
 再橫向豎向的看看上面的圖,哪裡需要用到變址?如的1、2、3、4紅筆處。

 

 

圖:地址變化

 

 那每一個紅筆標註的地方我們都可以用到一個變址,那有沒有必要呢,沒有必要。我們嘗試一下,先出動兩個變址寄存器,bx和si。分別用於表示2和4紅圈處。那我們就可以寫出下面的代碼來,

代碼後有相應的注釋,可以看看。

 

代碼:

 ;結構體定義<br />;char year[4] // 年<br />; 空格(1 Byte)<br />;int income (4 Bytes)// 收入<br />; 空格<br />;empoyer num (2 Bytes) // 僱員數<br />; 空格<br />;人均收入 (2 Bytes)<br />; 空格</p><p>; 要求:將data段的資料拷貝進table段資料,並結構化如上述格式,然後計算21年的人均收入</p><p>assume ds:data, es:table, cs:code, ss:stack</p><p>data segment<br /> db '1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982', '1983'<br /> db '1984', '1985', '1986', '1987', '1988', '1989', '1990', '1991', '1992'<br /> db '1993', '1994', '1995'</p><p> dd 16, 22, 382, 1356, 2390, 8000, 16000, 24486, 50065, 97479, 140417, 197514<br /> dd 345980, 590827, 803530, 1183000, 1843000, 2759000, 3753000, 4649000, 5937000 </p><p> dw 3, 7, 9, 13, 28, 38, 130, 220, 476, 778, 1001, 1442, 2258, 2793, 4037, 5635, 8226<br /> dw 11542, 14430, 15257, 17800<br />data ends </p><p>table segment<br /> db 21 dup ('year summ ne ?? ')<br />table ends </p><p>; 弄個棧,沒什麼用<br />; 就有時候用來騰出個寄存器<br />stacksegment<br />dw 2 dup(0)<br />stackends</p><p>codesegment</p><p>start:</p><p>; 設定data段,以及ds:bx指向data段的第一個單元,即ds:[bx]的內容就是data段第一個單元的內容<br />mov ax, data<br />mov ds, ax</p><p>; 設定table段<br />mov ax, table<br />mov es, ax</p><p>; 設定堆棧段<br />mov ax, stack<br />mov ss, ax<br />mov sp, 16</p><p>; 初始化三個變址寄存器<br />mov bx, 0<br />mov si, 0<br />mov di, 0</p><p>; 準備複製,需要用到迴圈,21次<br />mov cx, 21</p><p>s:<br />; 年<br />mov ax, ds:[bx+0]; 這裡寫個0是為了下面的對照,清晰點<br />mov es:[si+0], ax<br />mov ax, ds:[bx+2]<br />mov es:[si+2], ax</p><p>; 空格<br />mov al, 32<br />mov es:[si+4], al</p><p>; 收入<br />mov ax, ds:[bx+84]<br />mov es:[si+5], ax<br />mov ax, ds:[bx+86]<br />mov es:[si+7], ax</p><p>; 空格<br />mov al, 32<br />mov es:[si+9], al</p><p>; 僱員數<br />mov ax, ds:[bx+168];****這裡不滿足<br />mov es:[si+0ah], ax</p><p>; 空格<br />mov al, 32<br />mov es:[si+0ch], al</p><p>; 算人均收入,這裡小心高低位,<br />mov ax, ds:[bx+84]<br />mov dx, ds:[bx+86]<br />push cx; 臨時用一下cx,因為不可以 div ds:[bx+168]<br />mov cx, ds:[bx+168];*****這裡同上,也不滿足<br />div cx<br />pop cx<br />mov es:[si+0dh], ax</p><p>; 空格<br />mov al, 32<br />mov es:[si+0fh], al</p><p>add si, 16<br />add bx, 4<br />loop s</p><p>mov ax,4c00h<br />int 21h </p><p>code ends</p><p>end start

 

寫了上面的代碼之後,先編譯一遍,通過了,然後再放腦子裡跑一遍,這裡發現有兩個個地方不滿足變化的規律,就是下面這兩個地方:

1、
 ; 僱員數
 mov ax, ds:[bx+168] ;****這裡不滿足
 mov es:[si+0ah], ax
2、
 ; 算人均收入,這裡小心高低位,
 mov ax, ds:[bx+84]
 mov dx, ds:[bx+86]
 push cx   ; 臨時用一下cx,因為不可以 div ds:[bx+168]
 mov cx, ds:[bx+168] ;*****這裡同上,也不滿足
 div cx
 pop cx
 mov es:[si+0dh], ax

 

 第一次bx為0的時候,是正確的,但第二次bx加了4之後,[bx+168]就變成了172了,正確的應該是170,所以這裡是不滿足的。那怎麼辦呢?

 

 不著急,我們還有兩個變址寄存器沒出動呢,那我們現在就再出動 di 這個變址寄存器,來表示紅筆3處的變址。上面兩個不滿足的地方也修改如下:

 

1、
 ; 僱員數
 mov ax, ds:[di+168] ;****修改這裡
 mov es:[si+0ah], ax
2、
 ; 算人均收入,這裡小心高低位,
 mov ax, ds:[bx+84]
 mov dx, ds:[bx+86]
 push cx   ; 臨時用一下cx,因為不可以 div ds:[bx+168]
 mov cx, ds:[di+168] ;*****也修改這裡
 div cx
 pop cx
 mov es:[si+0dh], ax

3、
 ; di還要記住在最後加上2
 add si, 16
 add bx, 4
 add di, 2   ; 這裡記住要加上2
 loop s

 

做了上面這三步修改,就基本完成了,再在腦子裡過一遍,好像也沒什麼問題了,那就開啟DOS視窗,啟動我們的debug大炮,一步步的跟蹤,迴圈的第一次到第三次是比較關鍵的,需要慢慢調試,
調試到第四第五次、甚至21次都調試完了,我們發現,程式已經完成了。。。

 

以上就是我的分析解題思路,希望對你也有一定協助。下面就貼出最終完成的代碼:

 

;結構體定義<br />;char year[4] // 年<br />; 空格(1 Byte)<br />;int income (4 Bytes)// 收入<br />; 空格<br />;empoyer num (2 Bytes) // 僱員數<br />; 空格<br />;人均收入 (2 Bytes)<br />; 空格</p><p>; 要求:將data段的資料拷貝進table段資料,並結構化如上述格式,然後計算21年的人均收入</p><p>assume ds:data, es:table, cs:code, ss:stack</p><p>data segment<br /> db '1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982', '1983'<br /> db '1984', '1985', '1986', '1987', '1988', '1989', '1990', '1991', '1992'<br /> db '1993', '1994', '1995'</p><p> dd 16, 22, 382, 1356, 2390, 8000, 16000, 24486, 50065, 97479, 140417, 197514<br /> dd 345980, 590827, 803530, 1183000, 1843000, 2759000, 3753000, 4649000, 5937000 </p><p> dw 3, 7, 9, 13, 28, 38, 130, 220, 476, 778, 1001, 1442, 2258, 2793, 4037, 5635, 8226<br /> dw 11542, 14430, 15257, 17800<br />data ends </p><p>table segment<br /> db 21 dup ('year summ ne ?? ')<br />table ends </p><p>; 弄個棧,沒什麼用<br />; 就有時候用來騰出個寄存器<br />stacksegment<br />dw 2 dup(0)<br />stackends</p><p>codesegment</p><p>start:</p><p>; 設定data段,以及ds:bx指向data段的第一個單元,即ds:[bx]的內容就是data段第一個單元的內容<br />mov ax, data<br />mov ds, ax</p><p>; 設定table段<br />mov ax, table<br />mov es, ax</p><p>; 設定堆棧段<br />mov ax, stack<br />mov ss, ax<br />mov sp, 16</p><p>; 初始化三個變址寄存器<br />mov bx, 0<br />mov si, 0<br />mov di, 0</p><p>; 準備複製,需要用到迴圈,21次<br />mov cx, 21</p><p>s:<br />; 年<br />mov ax, ds:[bx+0]; 這裡寫個0是為了下面的對照,清晰點<br />mov es:[si+0], ax<br />mov ax, ds:[bx+2]<br />mov es:[si+2], ax</p><p>; 空格<br />mov al, 32<br />mov es:[si+4], al</p><p>; 收入<br />mov ax, ds:[bx+84]<br />mov es:[si+5], ax<br />mov ax, ds:[bx+86]<br />mov es:[si+7], ax</p><p>; 空格<br />mov al, 32<br />mov es:[si+9], al</p><p>; 僱員數,小心處理<br />mov ax, ds:[di+168]<br />mov es:[si+0ah], ax</p><p>; 空格<br />mov al, 32<br />mov es:[si+0ch], al</p><p>; 算人均收入,這裡小心高低位<br />mov ax, ds:[bx+84]<br />mov dx, ds:[bx+86]<br />push cx; 臨時用一下cx,因為不可以 div ds:[bx+168]<br />mov cx, ds:[di+168]; mov cx, ds:[bx+168]錯誤了。。。<br />div word ptr cx<br />pop cx<br />mov es:[si+0dh], ax</p><p>; 空格<br />mov al, 32<br />mov es:[si+0fh], al</p><p>add si, 16<br />add bx, 4<br />add di, 2; 這裡記住要加上2<br />loop s</p><p>mov ax,4c00h<br />int 21h </p><p>code ends</p><p>end start

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.