<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Switernal's Blogs

      看見每一種可能。

      博客園 首頁 新隨筆 聯(lián)系 訂閱 管理

      匯編實(shí)驗(yàn)3 轉(zhuǎn)移指令跳轉(zhuǎn)原理及其簡單應(yīng)用編程

      實(shí)驗(yàn)任務(wù)1

      源代碼

      點(diǎn)擊查看代碼
      assume cs:code, ds:data
      
      data segment
          x db 1, 9, 3
          len1 equ $ - x  ; 符號常量 , $指下一個(gè)數(shù)據(jù)項(xiàng)的偏移地址,這個(gè)示例中,是3
      
          y dw 1, 9, 3
          len2 equ $ - y  ; 符號常量 , $指下一個(gè)數(shù)據(jù)項(xiàng)的偏移地址,這個(gè)示例中,是9
      data ends
      
      code segment
      start:
          mov ax, data
          mov ds, ax
      
          mov si, offset x
          mov cx, len1
          mov ah, 2
          s1:mov dl, [si]
          or dl, 30h
          int 21h
          
          mov dl, ' '
          int 21h
      
          inc si
          loop s1
      
          mov ah, 2
          mov dl, 0ah
          int 21h
      
          mov si, offset y
          mov cx, len2/2
          mov ah, 2
          s2:mov dx, [si]
          or dl, 30h
          int 21h
      
          mov dl, ' '
          int 21h
      
          add si, 2
          loop s2
      
          mov ah, 4ch
          int 21h
      code ends
      end start
      

      實(shí)驗(yàn)結(jié)果

      根據(jù) Intel 白皮書LOOP指令的機(jī)器碼格式為:E2 cb(cb指一個(gè)字節(jié)單位)

      cb處是一個(gè)字節(jié)的偏移量,是一個(gè)8位有符號整數(shù),范圍在-128 ~ 127

      根據(jù)課堂和課本知識可知:LOOP本質(zhì)是一個(gè)近轉(zhuǎn)移,偏移量存儲時(shí)采用補(bǔ)碼表示

      問題①

      十六進(jìn)制(補(bǔ)碼):F2

      二進(jìn)制(補(bǔ)碼):1111 0010

      二進(jìn)制(原碼):1000 1110

      十進(jìn)制(原碼):-14

      根據(jù)LOOP指令定義:當(dāng)前IP + 有符號偏移量 = 跳轉(zhuǎn)地址

      當(dāng)前IP指向下一條指令開始地址,為001B,十進(jìn)制表示:27

      根據(jù)公式:27 + (-14) = 13

      13的十六進(jìn)制表示為:D,跳轉(zhuǎn)地址即000D,可以發(fā)現(xiàn)的確是代碼中跳轉(zhuǎn)的地址

      問題②

      十六進(jìn)制(補(bǔ)碼):F0

      二進(jìn)制(補(bǔ)碼):1111 0000

      二進(jìn)制(原碼):1001 0000

      十進(jìn)制(原碼):-16

      根據(jù)LOOP指令定義:當(dāng)前IP + 有符號偏移量 = 跳轉(zhuǎn)地址

      當(dāng)前IP0039,十進(jìn)制表示:57

      根據(jù)公式:57 + (-16) = 41

      41的十六進(jìn)制表示為:29,跳轉(zhuǎn)地址即0029,可以發(fā)現(xiàn)的確是代碼中跳轉(zhuǎn)的地址

      相關(guān)研究

      1. 關(guān)于匯編中的標(biāo)號(label)

      Intel 白皮書中,標(biāo)號一律被稱作label

      目前已經(jīng)學(xué)過的匯編中有兩種標(biāo)號方式,一種有冒號(:),一種沒有冒號

      上面的代碼中:

      assume cs:code, ds:data
      
      data segment
          x db 1, 9, 3
          len1 equ $ - x
      
          ...
          
      data ends
      
      code segment
      start:
      	...
      

      xlen1沒有冒號,而start有冒號。根據(jù)博客《匯編語言之 有冒號的標(biāo)號和沒冒號標(biāo)號的區(qū)別》的說法,區(qū)別在于xlen既可以當(dāng)做地址,也可以查看其中的內(nèi)容,而start只能作為地址使用。

      但是這篇博客寫的很含糊,不明不白。因此做了以下進(jìn)一步嘗試。

      嘗試1:如果在data段中給x加上冒號寫作這樣:

      data segment
          x: db 1, 9, 3
          len1 equ $ - x 
          
          ...
      

      會提示錯(cuò)誤:Missing or unreachable CS

      目前還沒搞清楚這是為什么,盲猜是因?yàn)?code>assume中將data段作為數(shù)據(jù)段,里面的代碼不會被執(zhí)行所導(dǎo)致的。

      但是可以知道,在data段中無法使用帶冒號的標(biāo)號(label)

      嘗試2:以下代碼段masm編譯階段會報(bào)錯(cuò):

      	a mov ax, 0
      	mov ax, word ptr a
      

      嘗試3:以下兩個(gè)代碼段編譯和運(yùn)行中均不會報(bào)錯(cuò):

      	a: mov ax, 0
      	mov ax, word ptr a
      
      	a db 1, 9, 3
      	mov ax, word ptr a
      

      兩段代碼中:

      第一段ax放入的均為a處指令開始的地址

      第二段ax放入的為數(shù)字1

      嘗試4:如下代碼段編譯和運(yùn)行中也不會報(bào)錯(cuò):

          a db 1, 9
          len1 = $ - a
          mov ax, len1
      
          b: db 1, 9
          len2 = $ - b
          mov ax, len2
      

      在debug中進(jìn)行反匯編:

      可以看到二者沒有什么差別

      可以發(fā)現(xiàn)

      1. 不帶冒號的標(biāo)號后只能跟偽指令,而帶冒號后可以跟任何指令
      2. 帶冒號和不帶冒號都可以作為指令的地址使用

      這里只做了簡單實(shí)驗(yàn)來研究加冒號和不加冒號兩種標(biāo)號形式的異同點(diǎn),但是資料過少且沒有時(shí)間,以后再做深入了解。

      2. LOOP指令

      在《Intel? 64 and IA-32 Architectures Software Developer’s Manual Volume 2 (2A, 2B, 2C & 2D): Instruction Set Reference, A-Z》(Intel白皮書)中,

      LOOP指令的機(jī)器碼結(jié)構(gòu)(Vol.2A 3-597):

      關(guān)于LOOP指令的描述:

      The target instruction is specified with a relative offset (a signed offset relative to the current value of the instruction pointer in the IP/EIP/RIP register). This offset is generally specified as a label in assembly code, but at the machine code level, it is encoded as a signed, 8-bit immediate value, which is added to the instruction pointer. Offsets of –128 to +127 are allowed with this instruction.

      目標(biāo)指令被指定為相對偏移量(相對于IP/EIP/RIP寄存器中指令指針的當(dāng)前值的有符號偏移)。這個(gè)偏移量在匯編代碼中通常被指定為一個(gè)標(biāo)號,但在機(jī)器碼層面,它被編碼為一個(gè)加在指令指針(IP)上的有符號8位立即數(shù)。這條指令允許的偏移量為-128到+127。

      實(shí)驗(yàn)任務(wù)2

      源代碼

      點(diǎn)擊查看代碼
      assume cs:code, ds:data
      
      data segment
          dw 200h, 0h, 230h, 0h
      data ends
      
      stack segment
          db 16 dup(0)
      stack ends
      
      code segment
      start:
          mov ax, data
          mov ds, ax
      
          mov word ptr ds:[0], offset s1  ; ds:[0] 存儲了s1的地址
          mov word ptr ds:[2], offset s2  ; ds:[2] 存儲了s2的地址
          mov ds:[4], cs                  ; ds:[4] 存儲了當(dāng)前段的段地址
      
          mov ax, stack
          mov ss, ax
          mov sp, 16
      
          call word ptr ds:[0]            ; word為短轉(zhuǎn)移,把 s1 處的 IP 進(jìn)棧, 然后跳轉(zhuǎn)到 s1 的地址
      s1: pop ax                          ; 把 s1 處的 IP 值送入 ax
      
          call dword ptr ds:[2]           ; dword為遠(yuǎn)轉(zhuǎn)移,把 s2 出的 CS:IP 值進(jìn)棧, 然后跳轉(zhuǎn)到 s2 處
      s2: pop bx                          ; 把 s2 的 IP 值送入 bx
          pop cx	                        ; 把 s2 的 CS 值送入 cx
          
          mov ah, 4ch
          int 21h
      code ends
      end start
      

      問題解答

      根據(jù)分析:(上面代碼中的注釋為分析過程)

      ax = s1 處的 IP

      bx = s2 的 IP

      cx = s2 的 CS

      實(shí)驗(yàn)結(jié)果

      和分析的結(jié)果是一致的。

      實(shí)驗(yàn)任務(wù)3

      僅實(shí)現(xiàn)任務(wù)中要求的源代碼

      點(diǎn)擊查看代碼
      ; 僅能打印byte長度的數(shù)字(0-255),可以實(shí)現(xiàn)不定位數(shù)
      assume ds:data, cs:code, ss:stack
      
      data segment
          x db 99, 72, 85, 63, 89, 97, 55
          len equ $ - x
      data ends
      
      stack segment
          dw 16 dup(?)
      stack ends
      
      code segment
      start:
          mov ax, data
          mov ds, ax
      
          mov ax, stack
          mov ss, ax
          mov sp, 32
      
          mov cx, len ; 由于數(shù)據(jù)都是byte型,所以len就是數(shù)據(jù)個(gè)數(shù)
          ; print循環(huán): 依次打印所有數(shù)字
          print:
              mov ah, 0                   ; 數(shù)據(jù)只有一個(gè)字節(jié),先把a(bǔ)h置0,子函數(shù)中除法是以ax作為被除數(shù)的
              mov al, byte ptr ds:[di]    ; 把數(shù)據(jù)放入al
              inc di                      ; di指針后移
      
              push cx             ; 把cx保存起來, 子程序中會修改cx值
      
              call printNumber    ; 打印數(shù)字
              call printSpace     ; 打印空格
      
              pop cx              ; 恢復(fù)cx
          loop print
          
          mov ah, 4ch
          int 21h
      
      ; 子程序: printNumber
      ; 功能: 打印數(shù)字
      ;   入口參數(shù): 
      ;       寄存器ax  (待輸出的數(shù)據(jù) --> ax)
      ;   局部變量說明: 
      ;       bx -> 存儲數(shù)字字符個(gè)數(shù)
      printNumber:
          mov bx, 0       ; 獲取之前位數(shù)為0
          ; 逐位獲取數(shù)字
          ; getEach循環(huán): 獲取每一位,然后壓入棧中
          getEach:
              mov dl, 10      
              div dl          ; 數(shù)據(jù)除10
      
              push ax         ; 將數(shù)字壓入棧中(ah余數(shù)在ax里了)
              inc bx          ; 位數(shù)+1
              
              mov ah, 0       ; ah是余數(shù),置0后ax表示除法的結(jié)果
              mov cx, ax      ; 除法結(jié)果賦給cx, 如果結(jié)果為0則說明所有位數(shù)都獲取完了
              inc cx          ; 由于loop時(shí)會-1,這里先+1,防止出現(xiàn)負(fù)數(shù)
      
          loop getEach
      
          ; 打印數(shù)字
          mov cx, bx          ; 先把bx存的數(shù)字位數(shù)賦給cx
          ; printEach循環(huán): 依次從棧中取出數(shù)字,逐位打印
          printEach:
              pop ax          ; 取出一位數(shù)
              add ah, 30h     ; ah是剛才除法的余數(shù),也就是需要得到的位數(shù),+30h是轉(zhuǎn)成對應(yīng)字符
              mov dl, ah      ; 放到dl, 用于打印
              mov ah, 2       ; 調(diào)用int 21h的2號子程序打印
              int 21h
          loop printEach 
      
          ret
      
      ; 子程序: printSpace
      ; 功能: 打印空格
      printSpace:
          mov ah, 2
          mov dl, 20h
          int 21h
          ret
      
      code ends
      end start
      

      任務(wù)要求的實(shí)驗(yàn)結(jié)果

      可以成功打印要求中的2位數(shù)。

      實(shí)際上,該代碼還可以打印0 ~ 255之間的任意數(shù)字,效果如下:

      改進(jìn)的源代碼

      點(diǎn)擊查看代碼
      ; 對task3.asm的修改, 可以打印0~2559不定位數(shù)的數(shù)字
      
      assume ds:data, cs:code, ss:stack
      
      data segment
      		; 改進(jìn): db換成dw
          x dw 999, 0, 856, 1024, 36, 97, 2559
          len equ $ - x
      data ends
      
      stack segment
          dw 32 dup(?)
      stack ends
      
      code segment
      start:
          mov ax, data
          mov ds, ax
      
          mov ax, stack
          mov ss, ax
          mov sp, 64
      
      		; 這里需要改
          mov cx, len/2 ; 由于數(shù)據(jù)都是word型,所以len/2才是數(shù)據(jù)個(gè)數(shù)
          ; print循環(huán): 依次打印所有數(shù)字
          print:
          		; 這里需要改, 數(shù)據(jù)讀進(jìn)ax而不是al
              mov ax, word ptr ds:[di]    ; 把數(shù)據(jù)放入al
              add di, 2                   ; di指針后移2字節(jié)
      
              push cx             ; 把cx保存起來, 子程序中會修改cx值
      
              call printNumber    ; 打印數(shù)字
              call printSpace     ; 打印空格
      
              pop cx              ; 恢復(fù)cx
          loop print
          
          mov ah, 4ch
          int 21h
      
      ; 子程序: printNumber
      ; 功能: 打印數(shù)字
      ;   入口參數(shù): 
      ;       寄存器ax  (待輸出的數(shù)據(jù) --> ax)
      ;   局部變量說明: 
      ;       bx -> 存儲數(shù)字字符個(gè)數(shù)
      printNumber:
          mov bx, 0       ; 獲取之前位數(shù)為0
          ; 逐位獲取數(shù)字
          ; getEach循環(huán): 獲取每一位,然后壓入棧中
          getEach:
              mov dl, 10      
              div dl          ; 數(shù)據(jù)除10
      
              push ax         ; 將數(shù)字壓入棧中(ah余數(shù)在ax里了)
              inc bx          ; 位數(shù)+1
              
              mov ah, 0       ; ah是余數(shù),置0后ax表示除法的結(jié)果
              mov cx, ax      ; 除法結(jié)果賦給cx, 如果結(jié)果為0則說明所有位數(shù)都獲取完了
              inc cx          ; 由于loop時(shí)會-1,這里先+1,防止出現(xiàn)負(fù)數(shù)
      
          loop getEach
      
          ; 打印數(shù)字
          mov cx, bx          ; 先把bx存的數(shù)字位數(shù)賦給cx
          ; printEach循環(huán): 依次從棧中取出數(shù)字,逐位打印
          printEach:
              pop ax          ; 取出一位數(shù)
              add ah, 30h     ; ah是剛才除法的余數(shù),也就是需要得到的位數(shù),+30h是轉(zhuǎn)成對應(yīng)字符
              mov dl, ah      ; 放到dl, 用于打印
              mov ah, 2       ; 調(diào)用int 21h的2號子程序打印
              int 21h
          loop printEach 
      
          ret
      
      ; 子程序: printSpace
      ; 功能: 打印空格
      printSpace:
          mov ah, 2
          mov dl, 20h
          int 21h
          ret
      
      code ends
      end start
      

      改進(jìn)后的實(shí)驗(yàn)結(jié)果

      改進(jìn)后的程序可以實(shí)現(xiàn)打印 0 ~ 2559之間的任意數(shù)字。

      一些說明

      1.關(guān)于改進(jìn)的代碼

      源代碼的數(shù)據(jù)存儲在字節(jié)單位,只能取0~255之間的數(shù)字。而改進(jìn)后數(shù)據(jù)存在字單位,理論上可以打印0 ~ 65535之間的任意數(shù)字。

      但是上面的實(shí)驗(yàn)結(jié)果中說最大只能打印到2559,而不是65535,這和除法運(yùn)算指令div有關(guān)。

      2. div指令的一些解釋

      王爽《匯編語言(第2版)》P169關(guān)于div指令的說明是:

      根據(jù)書上的說法,任意一個(gè)16位的被除數(shù)(十六進(jìn)制小于FFFF,也就是十進(jìn)制小于65535的數(shù))都可以放在ax中進(jìn)行除法運(yùn)算。

      但是在實(shí)際操作中(操作是:除數(shù)放在一個(gè)8位寄存器中(如bl)),被除數(shù)放在bx中把65535也就是FFFFh放在ax中,進(jìn)行十進(jìn)制除10運(yùn)算卻發(fā)生了錯(cuò)誤。同樣的,對0FFFh進(jìn)行除10運(yùn)算也出錯(cuò)了。而00FFh是不會出錯(cuò)的。

      這就奇了怪了。

      不過按書上的說明,16位被除數(shù)放在ax中,除法運(yùn)算后的商保存在al中,余數(shù)保存ah中。而alah都是8位的,因此商和余數(shù)應(yīng)該均小于8位。

      所以,其實(shí)div除法指令更確切的定義應(yīng)該是:

      如果除數(shù)為8位,被除數(shù)為16位,且進(jìn)行除法運(yùn)算后的余數(shù)均為8位,除數(shù)才能放在一個(gè)8位寄存器中,被除數(shù)放在AX中,且商和余數(shù)才會存在AHAL中。

      否則,即使除數(shù)是8位,仍應(yīng)當(dāng)放在一個(gè)16位的寄存器中,被除數(shù)則應(yīng)當(dāng)放在DX:AX中,如果是16位被除數(shù),則只放在AX即可,而商存在AX中,余數(shù)存在DX中。

      根據(jù) Intel 白皮書(《Intel? 64 and IA-32 Architectures Software Developer’s Manual Volume 2 (2A, 2B, 2C & 2D): Instruction Set Reference, A-Z》)中的說明:

      手冊的意思說,小于255的數(shù),被除數(shù)和結(jié)果都在AX中,而255 ~ 65535的數(shù)結(jié)果則當(dāng)DX:AX中。

      實(shí)際測試中,如果被除數(shù)放在16位寄存器中,除數(shù)是放在8位寄存器中,且商和余數(shù)都在8位范圍內(nèi),則可以正常計(jì)算且結(jié)果保存在AHAL中。而如果商或余數(shù)超過8位,則會出錯(cuò)。

      如果8位除數(shù)放在16位寄存器中(除了DX以外的寄存器),無論被除數(shù)是多少(0000-FFFFh),結(jié)果都會商保存在AX中,而余數(shù)保存在DX中。

      因此上面改進(jìn)的實(shí)驗(yàn)結(jié)果中提到的2559,根據(jù)上面的解釋,商和余數(shù)都在8位以內(nèi),由于做的是除10運(yùn)算,也就是十六進(jìn)制除A運(yùn)算,FF(商) * 0A + 09(余數(shù)) = 09FF09FF2559,因此上面的代碼最大可以支持到打印2559

      進(jìn)一步改進(jìn)的代碼

      限于篇幅,這里只展示修改后的printNumber子程序

      點(diǎn)擊查看代碼
      ; 對task32.asm的修改, 可以打印0~65535不定位數(shù)的數(shù)字
      
      ; 子程序: printNumber
      ; 功能: 打印數(shù)字
      ;   入口參數(shù): 
      ;       寄存器ax  (待輸出的數(shù)據(jù) --> ax)
      ;   局部變量說明: 
      ;       bx -> 存儲數(shù)字字符個(gè)數(shù)
      printNumber:
          mov bx, 0       ; 獲取之前位數(shù)為0
          ; 逐位獲取數(shù)字
          ; getEach循環(huán): 獲取每一位,然后壓入棧中
          getEach:
              ; 改進(jìn): 除數(shù)放在16位寄存器bp中
              mov bp, 10      ; 除10運(yùn)算
              mov dx, 0       ; 由于除數(shù)是16位寄存器,dx也是被除數(shù)一部分,需要置零      
              div bp          ; 數(shù)據(jù)除10
      
              push dx         ; 將數(shù)字壓入棧中(余數(shù)在dx里)
              inc bx          ; 位數(shù)+1
              
              mov cx, ax      ; 除法商賦給cx, 如果商為0則說明所有位數(shù)都獲取完了
              inc cx          ; 由于loop時(shí)會-1,這里先+1,防止出現(xiàn)負(fù)數(shù)
      
          loop getEach
      
          ; 打印數(shù)字
          mov cx, bx          ; 先把bx存的數(shù)字位數(shù)賦給cx
          ; printEach循環(huán): 依次從棧中取出數(shù)字,逐位打印
          printEach:
              pop dx          ; 取出一位數(shù)
              add dl, 30h     ; dl是剛才除法的余數(shù),也就是需要得到的位數(shù),+30h是轉(zhuǎn)成對應(yīng)字符
              mov ah, 2       ; 調(diào)用int 21h的2號子程序打印
              int 21h
          loop printEach 
      
          ret
      

      進(jìn)一步的結(jié)果

      至此,代碼task33.asm已經(jīng)可以實(shí)現(xiàn)輸出0 ~ 65535的任意數(shù)字了

      實(shí)驗(yàn)任務(wù)4

      源代碼

      點(diǎn)擊查看代碼
      assume cs:code, ds:data, ss:stack
      
      data segment
          string db 'try'
          len = $ - string
      data ends
      
      stack segment
          dw 2 dup(?)
      stack ends
      
      code segment
      start:
          
          mov ax, data
          mov ds, ax
      
          mov ax, stack
          mov ss, ax
          mov sp, 2
      
          mov cx, len    ; cs: 字符串長度
          mov ax, 0 
          mov si, ax     ; si: 0
      
          ; 打印頂部的綠色字符
          mov bl, 0Ah     ; bl: 顏色(背景黑+高亮+綠色:0 000 1 010)
          mov bh, 0       ; bh: 行號(第1行)
          call printStr
      
          ; 打印底部紅色字符
          mov bl, 0Ch     ; bl: 顏色(背景黑+高亮+綠色:0 000 1 100)
          mov bh, 24      ; bh: 行號(第25行)
          call printStr
      
          mov ah, 4ch
          int 21h
      
      ; 子程序: printStr
      ;    功能: 在指定行、以指定顏色,在屏幕上顯示字符串 
      ;    入口參數(shù):
      ;       字符串首字符地址 --> ds:si (其中,字符串所在段的段地址—> ds, 字符串起始地址的偏移地址—> si)
      ;       字符串長度      --> cx
      ;       字符串顏色      --> bl
      ;       指定行         --> bh (取值:0 ~ 24)
      printStr:
      
          mov al, bh      ; 把行號放在 al
          mov dl, 0A0h    ; 每行160字節(jié),放在 dl 中
          mul dl          ; 與行號相乘獲得行起始地址, al中存的是行起始地址
      
          mov di, ax      ; di存行起始地址
          mov ax, 0b800h    
          mov es, ax      ; 顯存段地址
      
          ; 開始打印
          ; cx已經(jīng)存了字符串?dāng)?shù)量, 直接循環(huán)就行
          push si                 ; 先保存si, 以便下次再用
          push cx                 ; 保存cx, 以便下次用
          ; 循環(huán)依次打印字符
          startToPrint:
              mov al, ds:[si]
              mov es:[di], al     ; 把ds:[si]的字符放進(jìn)es:[di]
              mov es:[di+1], bl   ; 放入顏色
              inc si
              add di, 2
          loop startToPrint
      
          pop cx                  ; 恢復(fù)cx
          pop si                  ; 恢復(fù)si
          ret         ; 打印完成, 返回 
      
      
      code ends
      end start
      

      實(shí)驗(yàn)結(jié)果

      可以看到,打印了符合預(yù)期的字符

      一些記錄

      1. printStr子程序中,進(jìn)行打印前,可以先將sicx入棧保存。由于字符串需要打印兩次重復(fù)利用,而這兩個(gè)寄存器的值在打印時(shí)需要修改(si控制讀入字符,cx控制打印字符個(gè)數(shù)的循環(huán)),因此先壓入棧中保存,打印結(jié)束后再彈出放回寄存器,下次可以繼續(xù)重復(fù)打印這一段字符串,簡化程序編寫

        這樣做的好處在于:

        ? 根據(jù)高級語言編寫函數(shù)的經(jīng)驗(yàn),除非需要,否則函數(shù)內(nèi)部最好不要修改外部變量。而sicx作為外部變量,在內(nèi)部需要進(jìn)行修改,因此先保存起來,修改完成后,在函數(shù)退出前再恢復(fù)回去,這樣相當(dāng)于把sicx拷貝為局部變量使用,不會修改外部變量

      2. 字符屬性值(僅作為記錄,來自王爽《匯編語言(第2版)》P189)

      實(shí)驗(yàn)任務(wù)5

      源代碼

      點(diǎn)擊查看代碼
      assume cs:code, ds:data
      
      data segment
          stu_no db '201983290048'
          len = $ - stu_no
      data ends
      
      code segment
      start:
          mov ax, data
          mov ds, ax
          mov di, 0
      
          call printStuNum    ; 調(diào)用打印子程序
      
          mov ah, 4ch
          int 21h
      
      ; 打印子程序:
      ;   參數(shù)說明:
      ;       學(xué)號字符串存儲在 -> ds:[di]
      printStuNum:
          mov ax, 0b800h
          mov es, ax      ; 控制顯存區(qū)域段指針
          mov si, 1       ; 顯存區(qū)域列指針
      
      ; 先把屏幕前24行背景打印成藍(lán)色
          mov al, 24      ; 前24行
          mov dl, 80      ; 每行80個(gè)字符需要修改顏色
          mul dl          ; 24*80, 獲得需要填充藍(lán)色的字符數(shù)
      
          mov cx, ax      
          printBlue:
              mov al, 17h         ; 藍(lán)底+白字:0 001 0 111 -> 17h
              mov es:[si], al     ; 把顏色填充到位
              add si, 2           ; 后移2個(gè)
          loop printBlue
      
          sub si, 1        ; 指針回退一個(gè), 從最后一行起始位置開始
      
      ; 打印最后一行
          mov ax, 80       
          sub ax, len      ; 80列 - 學(xué)號長度
          mov dl, 2        
          div dl           ; (80 - len)/2, 就是學(xué)號左右兩側(cè)需要填充'-'的長度
          mov dx, ax       ; 使用dx保存'-'的長度
          
          ; 調(diào)用打印'-'的子程序, 打印學(xué)號左側(cè)的'-'
          mov cx, dx
          call printSeparator 
      
          ; 打印學(xué)號字符串
          mov cx, len
          printNumber:
              mov al, ds:[di]		; 低位是字符
              mov ah, 17h				; 高位是顏色
              mov word ptr es:[si], ax	; 按字放入
              inc di
              add si, 2
          loop printNumber
      
          ; 再次調(diào)用打印'-'的子程序, 打印學(xué)號右側(cè)的'-'
          mov cx, dx
          call printSeparator
      
          ret
      
      ; 子程序: 打印分隔符'-'
      ;   參數(shù): 長度 -> cx
      ;        位置 -> es:[si]
      printSeparator:
          mov al, '-'
          mov ah, 17h
          mov word ptr es:[si], ax
          add si, 2
          loop printSeparator
          ret
      
      code ends
      end start
      

      實(shí)驗(yàn)結(jié)果

      代碼說明全部寫在代碼注釋中。

      可以看到,成功實(shí)現(xiàn)了要求實(shí)現(xiàn)的效果。

      總結(jié)與思考

      1. 課本上的內(nèi)容說的比較簡潔,很多細(xì)節(jié)沒有說的很清楚。這樣的好處是比較易懂,缺點(diǎn)是如果想知道更進(jìn)一步的原理就比較困難。之前偶然知道了 Intel 白皮書(《Intel? 64 and IA-32 Architectures Software Developer’s Manual》),這本手冊里可以查到 Intel 匯編指令的所有信息。常用的就是查看匯編指令的具體使用方法和機(jī)器碼等細(xì)節(jié)。
      2. 在研究過程中,關(guān)于loop和div兩個(gè)指令使用時(shí)產(chǎn)生了一些問題,由于國內(nèi)搜索引擎查找匯編相關(guān)資料時(shí)得到的內(nèi)容很少,幫助有限。而在查閱 Intel 白皮書后得到了很好的解決。
      3. 8086的實(shí)模式下控制顯存在屏幕上打印內(nèi)容相當(dāng)方便,只要知道了顯存的地址結(jié)構(gòu)就可以隨意修改屏幕上的顏色和內(nèi)容。
      4. 匯編中編寫子程序很像高級語言中的函數(shù),但是比函數(shù)更靈活一點(diǎn)。不過由于需要來回跳轉(zhuǎn),程序的結(jié)構(gòu)性可能不如高級語言來的好。
      5. 在實(shí)驗(yàn)任務(wù)1中對于標(biāo)號進(jìn)行了一些研究,但是無奈搜不到什么相關(guān)資料,只能靠猜測來解釋。
      6. 子程序需要合理分配寄存器,如果需要修改寄存器時(shí)最好先把寄存器的內(nèi)容壓棧,操作完后再恢復(fù),這樣可以在不同程序段中多次使用一個(gè)寄存器。
      posted on 2021-11-25 19:58  Switernal  閱讀(352)  評論(4)    收藏  舉報(bào)
      主站蜘蛛池模板: 国产精品熟女亚洲av麻豆| 亚洲男人天堂2018| 一区二区中文字幕久久| 欧美xxxxhd高清| 国产成人8X人网站视频| 亚洲 欧美 综合 另类 中字 | 麻豆一区二区三区香蕉视频| 亚洲精品日韩中文字幕| 欧美性猛交xxxx黑人| 中国国产免费毛卡片| 日韩三级一区二区在线看| 亚洲精品天堂成人片AV在线播放| 久久久亚洲欧洲日产国码αv | 重口SM一区二区三区视频| 欧美精欧美乱码一二三四区| 中国产无码一区二区三区| 辽宁省| 亚洲熟妇自偷自拍另欧美| 97在线精品视频免费| 麻豆国产传媒精品视频| 韩国美女福利视频一区二区| 麻豆成人精品国产免费| 亚洲中文字幕aⅴ天堂| 国产乱色熟女一二三四区| 欧美熟妇性XXXX欧美熟人多毛| 晋江市| 国语精品国内自产视频| 国产在线观看免费人成视频| 卫辉市| 亚洲乱色一区二区三区丝袜| 黑色丝袜脚交视频麻豆| 精品视频不卡免费观看| 浪潮av色综合久久天堂| 日韩人妻少妇一区二区三区| 亚洲中文无码手机永久| 成人午夜大片免费看爽爽爽| 激情久久av一区av二区av三区 | 亚洲人成绝网站色www| 91中文字幕一区二区| 欧美疯狂xxxxxbbbbb| 日区中文字幕一区二区|