溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

匯編語言中段如何定義和應用

發(fā)布時間:2022-03-04 14:13:34 來源:億速云 閱讀:321 作者:小新 欄目:開發(fā)技術

這篇文章主要為大家展示了“匯編語言中段如何定義和應用”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“匯編語言中段如何定義和應用”這篇文章吧。

    匯編語言中段如何定義和應用

    將一段內存定義為一個段,用一個段地址指示段,用偏移地址訪問段內的單元

    種類

    代碼段

    定義

    對于8086PC機,在編程時,可以根據需要,將一組內存單元定義為一個段。

    可以將長度為 N( N≤64KB )的一組代碼,存在一組地址連續(xù)、起始地址為 16的倍數的內存單元中,這段內存是用來存放代碼的,從而定義了一個代碼段。

    例如

    匯編語言中段如何定義和應用

    這段長度為 10 字節(jié)的字節(jié)的指令,存在從123B0H~123B9H的一組內存單元中,我們就可以認為,123B0H~123B9H這段內存單元是用來存放代碼的 ,是一個代碼段 ,它的段地址為123BH,長度為10字節(jié)。

    如何使得代碼段中的指令被執(zhí)行

    • CPU 只認被 CS:IP 指向的內存單元中的內容為指令。

    • 所以要將CS:IP指向所定義的代碼段中的第一條指令的首地址。

    • CS = 123BH,IP = 0000H。

    數據段

    定義

    我們可以將一組長度為N(N≤64K)、地址連續(xù)、起始地址為16的倍數的內存單元當作專門存儲數據的內存空間,從而定義了一個數據段。

    比如我們用123B0H~123B9H這段空間來存放數據:

    • 段地址:123BH

    • 長度:10字節(jié)

    將一段內存當作數據段,是我們在編程時的一種安排,我們可以在具體操作的時候 ,用 ds 存放數據段的段地址,再根據需要,用相關指令訪問數據段中的具體單元。

    DS和[address]

    我們要讀取10000H單元的內容

    CPU要讀取一個內存單元的時候,必須先給出這個內存單元的地址

    • 在8086PC中,內存地址由段地址和偏移地址組成。

    • 8086CPU中有一個 DS寄存器,通常用來存放要訪問的數據的段地址。

    將10000H(1000:0)中的數據讀到al中。

    mov bx,1000H

    mov ds,bx

    mov al,[0]

    mov 指令可以將一個內存單元中的內容送入一個寄存器。

    mov指令的格式:

    • mov 寄存器名,內存單元地址

    • “[…]”表示一個內存單元, “[…]”中的0表示內存單元的偏移地址。

    如何用mov指令從10000H中讀取數據?

    • 10000H表示為1000:0(段地址:偏移地址)

    • 將段地址1000H放入ds

    • 用mov al,[0]完成傳送(mov指令中的[]說明操作對象是一個內存單元,[]中的0說明這個內存單元的偏移地址是0,它的段地址默認放在ds中)

    如何把1000H送入ds?

    • 8086CPU不支持將數據直接送入段寄存器的操作,ds是一個段寄存器。(硬件設計的問題)

    • mov ds,1000H 是非法的。

    • 數據>>一般的寄存器>>段寄存器

    例如

    我們將123B0H~123BAH的內存單元定義為數據段,我們現在要累加這個數據段中的前3個單元中的數據,

    代碼如下:

    匯編語言中段如何定義和應用

    棧段

    棧空間當然也是內存空間一部分,它只是一段可以以一種特殊方式進行訪問的內存空間。

    操作方式

    棧有兩個基本的操作

    入棧:將一個新的元素放到棧頂

    出棧:從棧頂取出一個元素

    棧頂的元素總是最后入棧,需要出棧時,又最先被從棧中取出

    棧的操作規(guī)則:LIFO(Last In First Out,后進先出)

    8086CPU的入棧和出棧操作都是以字為單位進行的。

    注意:字型數據用兩個單元存放,高地址單元放高 8 位,低地址單元放低8 位。

    8086CPU提供入棧和出棧指令

     SS:SP  

    8086CPU中,有兩個寄存器:

    • 段寄存器SS  存放棧頂的段地址

    • 寄存器SP  存放棧頂的偏移地址

    任意時刻,SS:SP指向棧頂元素。

    SS和SP只記錄了棧頂的地址,依靠SS和SP可以保證在入棧和出棧時找到棧頂。

    棧頂超界的問題

    種類

    • 當棧滿的時候再使用push指令入棧,

    • 棧空的時候再使用pop指令出棧,

    8086CPU不保證對棧的操作不會超界。

    8086CPU 只知道棧頂在何處(由SS:SP指示),而不知道讀者安排的??臻g有多大。

    8086CPU的工作機理,只考慮當前的情況:

    • 當前棧頂在何處;

    • 當前要執(zhí)行的指令是哪一條。

    解決辦法

    • 要根據可能用到的最大棧空間,來安排棧的大小,防止入棧的數據太多而導致的超界

    • 執(zhí)行出棧操作的時候也要注意,以防棧空的時候繼續(xù)出棧而導致的超界。

    push、pop指令

    定義

    push和pop指令是可以在寄存器和內存之間傳送數據的。

    PUSH(入棧)

    push ax:將寄存器ax中的數據送入棧中;

    執(zhí)行過程 push ax

    (1)SP=SP–2;

    (2)將ax中的內容送入SS:SP指向的內存單元處,SS:SP此時指向新棧頂。

    圖示

    匯編語言中段如何定義和應用

    入棧時,棧頂從高地址向低地址方向增長

    POP(出棧)

    pop ax :從棧頂取出數據送入ax。執(zhí)行過程 (1)將SS:SP指向的內存單元處的數據送入ax中;(2)SP = SP+2,SS:SP指向當前棧頂下面的單元,以當前棧頂下面的單元為新的棧頂。

    圖示

    匯編語言中段如何定義和應用 

    注意:

    出棧后,SS:SP指向新的棧頂 1000EH,pop操作前的棧頂元素,1000CH 處的2266H 依然存在 ,但是,它已不在棧中。

    當再次執(zhí)行push等入棧指令后,SS:SP移至1000CH,并在里面寫入新的數據,它將被覆蓋。

    格式

    (1)

    push 寄存器:將一個寄存器中的數據入棧

    pop 寄存器:出棧,用一個寄存器接收出棧的數據

    例如:push axpop bx

    (2)

    push 段寄存器:將一個段寄存器中的數據入棧 pop

    段寄存器:出棧,用一個段寄存器接收出棧的數據

    例如:push dspop es

    (3)

    push 內存單元:將一個內存單元處的字入棧(棧操作都是以字為單位)

    pop 內存單元:出棧,用一個內存字單元接收出棧的數據

    例如:push [0] pop [2]

    指令執(zhí)行時 ,CPU 要知道內存單元的地址,可以在 push、pop 指令中給出內存單元的偏移地址,段地址在指令執(zhí)行時,CPU從ds中取得。

    注意

    與mov指令不同的是,push和pop指令訪問的內存單元的地址不是在指令中給出的,而是由SS:SP指出的。

    CPU執(zhí)行mov指令只需一步操作,就是傳送,而執(zhí)行push、pop指令卻需要兩步操作

    執(zhí)行push時:先改變SP,后向SS:SP處傳送。

    執(zhí)行pop時: 先讀取SS:SP處的數據,后改變SP。

    push、pop 等棧操作指令,修改的只是SP。也就是說,棧頂的變化范圍最大為:0~FFFFH。

    提供:SS、SP指示棧頂;改變SP后寫內存的入棧指令;讀內存后改變SP的出棧指令。

    棧段定義

    • 可以根據需要 ,將一組內存單元定義為一個段

    • 比如我們將10010H~1001FH 這段長度為 16 字節(jié)的內存空間當作棧來用,以棧的方式進行訪問。

    • 我們可以將長度為 N(N ≤64K )的一組地址連續(xù)、起始地址為16的倍數的內存單元,當作棧來用,從而定義了一個棧段

    • 這段空間就可以成為棧段,段地址為1000H,大小為16字節(jié)

    • 如何使的如push、pop 等棧操作指令訪問我們定義的棧段

    • 將SS:SP指向我們定義的棧段。

    思考

    我們將10000H~1FFFFH這段空間當作棧段 ,SS=1000H ,??臻g大小為64KB ,棧最底部的字單元地址為1000:FFFE。

    任意時刻,SS:SP指向棧頂,當棧中只有一個元素的時候,SS=1000H,SP=FFFEH。

    棧為空,就相當于棧中唯一的元素出棧,出棧后,SP=SP+2。

    SP原來為FFFEH,加2后SP=0,所以,當棧為空的時候,SS=1000H,SP=0。

    任意時刻,SS:SP指向棧頂元素,當棧為空的時候 ,棧中沒有元素 ,也就不存在棧頂元素,所以SS:SP只能指向棧的最底部單元下面的單元 ,該單元的偏移地址為棧最底部的字單元的偏移地址+2 ,棧最底部字單元的地址為1000:FFFE,所以棧空時,SP=0000H。

    訪問

    對于數據段,將它的段地址放在 DS中,用mov、add、sub等訪問內存單元的指令時,CPU就將我們定義的數據段中的內容當作數據段來訪問;

    對于代碼段,將它的段地址放在 CS中,將段中第一條指令的偏移地址放在IP中,這樣CPU就將執(zhí)行我們定義的代碼段中的指令;

    對于棧段,將它的段地址放在SS中,將棧頂單元的偏移地置放在 SP 中,這樣CPU在需要進行棧操作的時候,比如執(zhí)行 push、pop 指令等,就將我們定義的棧段當作棧空間來用。

    可見,不管我們如何安排 ,CPU 將內存中的某段內存當作代碼 ,是因為CS:IP指向了那里;CPU將某段內存當作棧 ,是因為 SS:IP 指向了那里

    比如我們將10000H~1001FH安排為代碼段,并在里面存儲如下代碼:

    匯編語言中段如何定義和應用

    設置CS=1000H,IP=0,這段代碼將得到執(zhí)行。

    可以看到,在這段代碼中,我們又將10000H~1001FH 安排為棧段和數據段。

    10000H~1001FH這段內存,既是代碼段,又是棧段和數據段。

    一段內存,可以既是代碼的存儲空間,又是數據的存儲空間,還可以是??臻g,也可以什么也不是。

    關鍵在于CPU中寄存器的設置,即:CS、IP、SS、SP、DS的指向。

    段前綴

    在訪問內存單元的指令中,用于顯式地指明內存單元的段地址的“ds:”、“cs:”、“ss:”或“es:”

    應用

    場景1

    問題:將內存ffff:0~ffff:b段元中的數據拷貝到 0:200~0:20b單元中。

    分析

    (1) 0:200~0:20b單元等同于0020:0~0020:b單元,它們描述的是同一段內存空間

    (2)拷貝的過程應用循環(huán)實現,簡要描述如下:

    • 初始化:X=0 循

    • 環(huán)12次

    將ffff:X單元中的數據送入0020:X(需要用一個寄存器中轉)

    X=X+1

    (3)在循環(huán)中,源單元ffff:X和目標單元的0020:X的偏移地址X是變量。我們用bx來存放

    (4)我們用將0:200~0:20b用0020:0~0020:b描述,就是為了使目標單元的偏移地址和源始單元的偏移地址從同一數值0開始。

    問題

    因源單元ffff:X和目標單元0020:X 相距大于64KB,在不同的64KB段里,程序中,每次循環(huán)要設置兩次ds。

    這樣做是正確的,但是效率不高。

    解決

    我們可以使用兩個段寄存器分別存放源單元ffff:X和目標單元0020:X的段地址,這樣就可以省略循環(huán)中需要重復做12次的設置ds的程序段。

    匯編語言中段如何定義和應用

    改進的程序中,使用 es 存放目標空間0020:0~0020:b的段地址,用ds存放源空間ffff:0~ffff:b的段地址。

    在訪問內存單元的指令“mov es:[bx],al”中 ,顯式地用段前綴 “es:” 給出單元的段地址,這樣就不必在循環(huán)中重復設置ds

    場景2

    Debug和匯編編譯器Masm對指令的不同處理

    Debug中

    • mov ax,[0]

    • 表示將ds:0處的數據送入al中。

    在匯編源程序中,指令“mov ax,[0]”被編譯器當作指令“mov ax,0”處理。

    解決:利用段前綴顯性的指出段地址

    以上是“匯編語言中段如何定義和應用”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業(yè)資訊頻道!

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI