1. 程式人生 > >8086彙編學習之[BX],CX暫存器與loop指令,ES暫存器等

8086彙編學習之[BX],CX暫存器與loop指令,ES暫存器等

一、彙編程式的基本格式:

1、基本格式與解析:

assume cs:codeseg   //assume假設CS暫存器與codeseg段有關聯,codeseg段本就是程式碼段

codeseg segment //段開始,codeseg為段名,可隨意命名只要不和偽指令、指令等衝突即可

    mov ax,4C00H
    int 21H

codeseg ends    //段結束

end //程式結束標誌

以上格式中assume、segment、ends、end均為偽指令,由編譯器識別翻譯。assume的關聯並非必須。

    mov ax,4C00H
    int 21H

而這兩條指令的功能就是實現程式返回,在DOS中如果是command將可執行程式載入入記憶體,command就設定CPU的CS:IP指向程式的第一條指令,及程式的入口,當程式從入口開始執行完畢以後,“mov ax,4C00H”、“int 21H”看來那個條指令執行後返回到command中,CPU則繼續執行command,如果是Debug將可執行程式載入進記憶體中,則返回後回到Debug(類似於在Shell中執行的子程序(”main(){return 0;})執行完畢會返回shell,shell則繼續執行。只不過DOS是單程序,而Linux的Shell是時間片輪轉多程序)。

2、注意問題:

(1)不允許運算元以字母開頭:
在Debug中一行一行指令輸入時,我們可以以字母開頭,但是在編輯器編輯、MASM編譯、LINK連線時,就不能以字母開頭,否則會報未定義錯誤,如果遇到以字母開頭的,在其前面加一個0即可。
eg:

mov ax,B810H    //(×)
mov ax,47120    //(√),B810H的十進位制
mov ax,0B810H   //(√),十六進位制修改(修正)
mov al,E7H  //(×)
mov al,0E7H //(√)

關於以字母開頭會提示錯誤的測試如下:
這裡寫圖片描述

(2)-g cs:ip、-g ip 快速執行多行
-g ip 省略cs,預設去ds暫存器中找。

//eg:    這是編譯過程中生成的“.lst”檔案中的一部分
                            assume cs:codeseg 

       0000                 codeseg segment 

       037F:0000  B8 1000           mov ax,1000H 
       037F:0003  8E D8             mov ds,ax 

       037F:0005  BB 0000           mov bx,0 
       037F:0008  8B 07             mov ax,ds:[bx] 
       037F
:000A BB 0002 mov bx,2 037F:000D 8B 07 mov ax,ds:[bx] 037F:000F BB 0004 mov bx,4 037F:0012 8B 07 mov ax,ds:[bx] 037F:0014 BB 0006 mov bx,6 037F:0017 8B 07 mov ax,ds:[bx] 037F:0019 BB 0008 mov bx,8 037F:001C 8B 07 mov ax,ds:[bx] 037F:001E BB 000A mov bx,10 037F:0021 8B 07 mov ax,ds:[bx] 037F:0023 B8 4C00 mov ax,4C00H 037F:0026 CD 21 int 21H 037F:0028 codeseg ends end //debug dabx.exe //直接-g 000F //將000F之前的執行完停到"mov bx,4"這一行等待執行

上面這段程式碼編譯執行前:

;-d 2000:1000
;00 00 00 00 00 00 00 00--00 00 00 00 00 00 00 00

編譯->連線->裝載->執行後,結果為:

;-d 2000:1000
;BE 00 EE 00 EE EE EE 00--00 00 00 00 00 00 00 00

(3)、用[bx]代替[n]:
在上面我們已經用到[bx]了。至於為什麼要用[bx]代替[n],同樣是因為在Debug中會自動識別為ds:[n]段地址+偏移地址的格式,但是在編輯器中編輯並通過masm編譯後,這種[n]形式的都會被編譯器解析為值,eg:mov ax,[2]會被解析為mov ax,2,但是並不是說必須用[bx]的形式,只是[n]的形式必須配合”段地址暫存器:[n]”的形式一起使用(“這裡的不能字母開頭”、“[bx]代替[n]”等問題都是Debug與MASM對指令的不同處理方式引起的)。

mov ax,[0]  //對MASM來說錯誤
mov ax,ds:[0]   //正確
mov ax,ds:[bx]  //正確
mov ax,[bx] //正確

3、程式載入:

編譯->連線->裝載(載入)->執行的過程,我們說說程式在記憶體中的裝載情況:
這裡寫圖片描述
,測試如下:
這裡寫圖片描述

二、loop指令、CX暫存器等:

1、簡介:

在C語言中,我們使用過goto語句:

loop_one:
    int x = 5;
    ...
    goto loop_one;

而在彙編中的迴圈(loop)與goto語句及其相似,其格式為:

loop_one:
    mov ax,5
    ...
    loop loop_one

我們C中goto迴圈何時結束的條件一般在if..else判斷中,而彙編則是將迴圈結束條件放在了CX暫存器中。給CX一個初始值(迴圈次數),當loop指令中標號(如:loop_one)所標識的地址被再次訪問,CX的值減去1(即loop執行一次,CX值自減1)。當CX的值為0時結束迴圈,執行loop指令的下一條指令。loop_one其實就是個地址,loop loop_one就是跳躍到loop_one所標識的地址去(IP暫存器修改為loop_one的地址),從該地址繼續解析指令並執行。loop指令的迴圈形式像do{}while();而不像while(){},因為loop至少會執行一次。那麼CX初始化為0時,先減到FFFF再判斷,而不是直接判斷等於0退出迴圈。並且這是倒計時式的迴圈,不是計數式的迴圈。
(知識點:在用Debug的-p除錯時可以不進入迴圈/call調中去逐句執行。-p:特點是當遇到int中斷程式時,會一次性將呼叫的中斷程式執行完;而-t:的特點是當遇到int中斷程式時會追蹤到呼叫的中斷程式裡面去。像loop、call、int 21H等都屬於int中斷,所以通常會用到-p而不是-t)

2、應用:

例一:計算FFFF:0~FFFF:F的位元組型資料的和,結果儲存到DX中:

assume cs:codeseg

codeseg segment
        ;設定ds暫存器為FFFFH
        mov bx,0
        mov ax,0FFFFH
        mov ds,ax

        mov dx,0        ;初始偏移地址為0
        mov cx,16       ;FFFF:0~FFFF:F共16個位元組,迴圈16次
        mov ax,0        ;位元組型資料,需要8位暫存器,但是8位可能累加時溢位,必須用16位,所以高位必須清零,之後向AL存資料,所以只需清零一次

    addNumber:
        mov al,ds:[bx]  ;位元組型資料,需要8位暫存器
        add dx,ax       ;累加
        inc bx          ;inc指令將bx的值自加1,即偏移地址增大一個位元組
        loop addNumber  ;條件(CX)減1

        mov ax,4C00H
        int 21H

codeseg ends

end

測試結果:
這裡寫圖片描述

2、將FFFF:0~FFFF:F的資料複製到0:200~020F中:

assume cs:codeseg

codeseg segment

        mov cx,16
        mov bx,0
    ;由於只用一個ds資料段地址暫存器,而需要在兩段資料段之間迴圈操作,就需要用中間暫存器先儲存被複制的物件,然後修改ds暫存器,最後將中間暫存器中的一個位元組mov到目標地址中
    copyNumber:
        mov ax,0FFFFH
        mov ds,ax
        mov al,ds:[bx]  ;儲存到中間暫存器

        mov ax,0020H    ;修改ds暫存器,0020*10:0==0:200
        mov ds,ax
        mov ds:[bx],al  ;中間暫存器轉移

        inc bx  ;操作下一個位元組
        loop copyNumber

        mov ax,4C00H
        int 21H

codeseg ends

end

三、ES暫存器:

由於上例題中,用一個ds暫存器在兩段地之間來回修改,使得指令數隨著迴圈次數增大而成倍增加,那麼我們是否可以借用其它段地址暫存器(cs:[bx]、ss:[bx]、es:[bx]來優化)呢?但是cs和ss都已有他用,只有ES空閒,ES暫存器也是一個段地址暫存器,我們可以用ES段地址暫存器對上例進行優化:
DS:資料從哪裡來
ES:資料到哪裡去
當然ES和DS在下例中可以替換位置,但是注意:ds可以不寫成ds:[bx]的形式,因為[bx]預設是ds:[bx],而ES就必須寫成es:[bx],否協會被解析為ds:[bx]。

assume cs:codeseg

codeseg segment

        mov cx,16
        mov bx,0

        mov ax,0FFFFH  ;ds暫存器儲存被複制者段地址
        mov ds,ax
        mov ax,0020H  ;es存放目標段地址
        mov es,ax

    ;用ES暫存器優化:
    copyNumber:
        mov dl,ds:[bx]
        mov es:[bx],dl  
        inc bx
        loop copyNumber

        mov ax,4C00H
        int 21H

codeseg ends

end

測試結果:
這裡寫圖片描述
還有一點問題:由於彙編是直接對實體記憶體進行操作,所以不安全的記憶體操作很可能發生,為了避免使用已經有資料的記憶體,我們要儘量在0:200~0:2FF的256個位元組中進行程式設計(因為DOS以及其他合法程式一般會使用該段空間)。

相關推薦

8086彙編學習[BX]CXloop指令ES

一、彙編程式的基本格式: 1、基本格式與解析: assume cs:codeseg //assume假設CS暫存器與codeseg段有關聯,codeseg段本就是程式碼段 codeseg segment //段開始,codeseg為段名,可

8086彙編學習定址方式、資料型別以及幾個資料操作指令

一、and、or指令與應用: 1、描述: and指令:按位與 or指令:按位或 and register value or register value 其按位操作關係與C、C++等是一樣的,無需贅言。 eg:

2018年11月13日Java學習關鍵字static(類成員和類方法)單例設計類的成員:初始化塊

1.類變數(類屬性)由該類的所有例項共享 static 修飾的變數就是類變數,可以直接不建立物件訪問靜態成員,所有例項可以共同修改這個值 2.類方法 static修飾的方法可以用類名.方法名()訪問 在static方法內部只能訪問類的static屬性,不能訪問

進入保護模式-彙編學習

在真實模式下由於對記憶體的保護不是特別的完善,一個段可以任意訪問訪問不是該段範圍內的記憶體。例如以下一個小例子 mov cx,0x8000 push ds mov ds,cx mov [0x05],dx pop ds 這個例子就說明了先儲存當前的資料段地址之後在修改其他段的

Python學習路(2)——標準資料型別續——列表元組字典集合

0.Python之禪 可以通過在python直譯器中輸入import this 檢視python應該注意的一些規範與原則,如下: 1.列表 元素用方括號括起,元素之間用逗號隔開,如[1,2,3,4] 三大特點: (1)異構性 列表裡想裝啥就裝啥,即:他可以包含不同種類、

Java學習使用net.lingala.zip4j.core.ZipFile解壓縮檔案帶解壓縮排度

import java.io.File; import net.lingala.zip4j.core.ZipFile; import net.lingala.zip4j.exception.ZipException; import net.lingala.zip4j.progress.ProgressMoni

8086彙編初學貪吃蛇

前言 一直沒想過要去學習彙編,覺得需要用匯編的場合無非三種: 1. 與硬體結合很緊密高階語言做不到 2. 時空效率要求甚高演算法層面已不能優化到 3. 逆向破解等只能用某些途徑看其彙編指令 其餘情況下,用匯編無異於有炮不用偏用鳥槍。 本來準備等

機器學習 SVM VC維度、樣本數目經驗風險最小化的關系

能力 pan dsm 過擬合 引入 div 不但 機器 con VC維在有限的訓練樣本情況下,當樣本數 n 固定時。此時學習機器的 VC 維越高學習機器的復雜性越高。VC 維反映了函數集的學習能力,VC 維越大則學習機器越復雜(容量越大)。

JAVA基礎學習路(六)數組方法參數的傳遞

就是 .com 另一個 AS oid span 參數 spa nbsp 通常,向方法中傳遞的都是基本數據類型,而向方法中傳遞數組時,就需要考慮內存的分配 public class test2 { public static void main(String a

機器學習數學系列(一)矩陣矩陣乘法

1.對於矩陣的認識應當把它看成是多個向量的排列表或把矩陣看成行向量,該行向量中的每個元素都是一個列向量,即矩陣是複合行向量。如下圖所示。 2.對於下面這個矩陣的乘法有兩種看法: (1)矩陣將向量[b1,b2,b3].T進行了運動變換,這種變換可以是同空間內變換,也可以是不同空間間的變換;

Vue學習路(六)---父元件子元件之間的資料傳遞

前面我講了基本元件的寫法,現在一起學下父元件怎樣傳遞資料到子元件,以及子元件傳遞資料到父元件的 1.父元件傳遞資料到子元件 1.1 通過props傳遞 父元件App.vue中 <component-a big-num=98></component-a&g

薦書丨深度學習美——AI時代的資料處理最佳實踐

點選上方“程式人生”,選擇“置頂公眾號”第一時間關注程式猿(媛)身邊的故事零入門 | 高可讀|

Linux 學習Shell 基礎——Bash基本功能——別名快捷鍵

1、命令別名 [[email protected] ~]# alias 別名='原命令’ #設定命令別名 [[email protected] ~]# alias # 查詢命令別名 詳細介紹: 1)別名就是給系統中的某個命令起個新名稱,方便使用者根據自

個人js學習例項-點選按鈕實現全選反選及封裝函式呼叫前後

原始: <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="wid

本體(ontology)學習我見——Jena規則編寫——中文顯示owl:inverseOf推理結果不全

     本體建立以後,接下來就是考慮怎樣去使用本體。之前已經說過,我的主要用途就是找出本體例項中的衝突(inconsistent)以及推匯出新的關係,而這兩者都要用到規則。筆者主要運用運用Jena提供的基於自定義規則的推理機來實現以上兩點,當然你也可以使用Jena+pell

WebService學習旅(三)JAX-WSSpring整合釋出WebService

Spring本身就提供了對JAX-WS的支援,有興趣的讀者可以研究下Spring的Spring-WS專案,專案地址: http://docs.spring.io/spring-ws/sites/1.5/downloads/releases.html 基於Sp

大資料學習路65-scala的泛型隱式轉換

scala的泛型用[] 正常寫法:extends Comparable[Boy] [T <: Comparable]    上界  upper bound [T  >: Comparable]   下界   lower bound [T : Compara

Vue學習七(動畫鉤子,Vuex的使用購物車的展示)

飛入購物車的動畫 步驟: 1、建立一個div,裡面放一個img,把它放在加入購物車的位置,並且隱藏 1.1 建立了div和img,寫了必要的樣式 1.2 讓div剛開始的時候,顯示到加入購物車這個位置,那麼就必須

android物聯網初步利用手機藍芽微控制器通訊實現led燈開關和定時

                轉載請註明出處。                 這次是一個課程設計,利用微控制器開發一個物聯網系統。我們利用了手機藍芽與單片機板子上的藍芽通訊,通過 控制訊號來控制微控制器上led燈的亮滅和定時。  網上有很多的搜尋藍芽的例程,大家可以自己

C++隨筆--1)函式外部變數的定義宣告問題2)程式的編譯問題

1) 函式,外部變數的定義和宣告問題     1)(2017-9-17日目前認為) 區域性變數無論定義時賦值與否 (int a 或  int a = 2),我們都可以大概認為此時 定義和 宣告是一回事,但通過反彙編我們可以知道如果沒有賦初值那麼其實只是