1. 內(nèi)存中字的存儲(chǔ)
數(shù)字:20000,十六進(jìn)制:4E20H微姊。
4E20 一共 16 位洼哎,我們稱之為一個(gè)字烫映。
CPU中沼本,使用 16 位寄存器存儲(chǔ)一個(gè)字。并用高 8 位寄存器來(lái)存放高位字節(jié)(4E)锭沟,低 8 位寄存器存放低位字節(jié)(20)抽兆。如圖 4-2 ,使用 寄存器 AX 存放4E20H族淮, 圖 4-1 右側(cè)顯示了寄存器低位和高位存儲(chǔ)情況
如圖 4-1 左側(cè)辫红,在內(nèi)存中,每個(gè)內(nèi)存單元是字節(jié)單元(一個(gè)單元存儲(chǔ)一個(gè)字瞧筛, 8 位)厉熟,那么一個(gè)字要兩個(gè)地址連續(xù)的內(nèi)存單元來(lái)存放。同理较幌,低地址單元存放低位字節(jié)(20)揍瑟,高地址單元存放高位字節(jié)(4E)。
如圖 4-3 黃色區(qū)域中的的兩個(gè)連續(xù)的內(nèi)存單元組成了一個(gè)字單元乍炉。高地址內(nèi)存單元存放字型數(shù)據(jù)的高位字節(jié)绢片,低地址內(nèi)存單元存放字型數(shù)據(jù)的低位字節(jié)。
問(wèn)題分析:
對(duì)于圖 4-1:
1)0 地址單元中存放的字節(jié)型數(shù)據(jù)是多少岛琼?
2)0 地址字單元中存放的字型數(shù)據(jù)是多少底循?
3)2 地址單元中存放的字節(jié)型數(shù)據(jù)是多少?
4)2 地址單元中存放的字型數(shù)據(jù)是多少槐瑞?
5)1 地址子單元中存放的字型數(shù)據(jù)是多少熙涤?
分析:
1)12H
2) 4E12H
3) 12H
4) 0012H
- 124EH
任何兩個(gè)地址連續(xù)的內(nèi)存單元, N 號(hào)單元和 N+1 號(hào)單元困檩,可以將它們看成兩個(gè)內(nèi)存單元祠挫,也可以看成一個(gè)地址為 N 的字單元的高位字節(jié)單元和低位字節(jié)單元
2. DS 和 [address]
CPU 要讀寫一個(gè)內(nèi)存單元中的數(shù)據(jù),就必須先給出這個(gè)內(nèi)存單元的第一種悼沿,而 8086CPU 內(nèi)存地址有段地址和偏移地址組成等舔。 在 8086CPU 中有個(gè)寄存器 DS,這個(gè)寄存器就是用來(lái)存放要訪問(wèn)的內(nèi)存單元的段地址糟趾。
比如慌植,我們要讀取 10000H 單元的內(nèi)容,可以用如下的程序段進(jìn)行:
mov bx, 1000
mov ds, bx
mov al,[0]
上面的三條命令將 10000H(1000:0)中的數(shù)據(jù)讀到 al 中义郑。如圖演示:
如上圖演示蝶柿,最終 ax 寄存器中存放了 0012H 也就是內(nèi)存地址 10000H 中的數(shù)據(jù)。
對(duì)于 mov 指令功能:
① 將數(shù)據(jù)直接送入寄存器內(nèi) (mov bx,1000,將 1000H 送入寄存器 bx 中)
② 將一個(gè)寄存器中的內(nèi)容送入另一個(gè)寄存器 (mov ds,bx 將 bx 內(nèi)容送入到 ds 中)
除此之外非驮,也可以通過(guò) mov 指令將一個(gè)內(nèi)存單元中的內(nèi)容送入到一個(gè)寄存器中只锭。
mov ax, [0]
上面這條命令中 [0] 表示的是偏移地址,但是僅僅有偏移地址是不能定位一個(gè)內(nèi)存單元的院尔,對(duì)于 8086CPU 而言會(huì)自動(dòng)從去取 DS 寄存器中的數(shù)組作為內(nèi)存單元的段地址蜻展。
再來(lái)看一下,如何用 mov 指令從 10000H 中讀取數(shù)據(jù):
- 10000H 用段地址 和 偏移地址表示為: 1000:0
- 通過(guò) mov bx,1000 mov ds,bx 將段地址 1000H送入寄存器 ds 中
- 然后通過(guò) mov al,[0] 將數(shù)據(jù)從內(nèi)存單元 1000:0 取出并送入寄存器al(ax低位寄存器)中
這里可能看出一個(gè)問(wèn)題邀摆,就是第 2 步的時(shí)候纵顾,為什么不直接通過(guò) mov ds,1000 將 1000H 直接送入寄存器: DS ?
這屬于 8086CPU 硬件設(shè)計(jì)問(wèn)題栋盹,DS 是一個(gè)段寄存器施逾,8086CPU 不支持直接將數(shù)據(jù)送入段寄存器的操作。
問(wèn)題:寫幾條指令將 al 中的數(shù)據(jù)送入內(nèi)存單元 10000H 中(具體操作見(jiàn)下面的gif):
mov bx,1000
mov ds,bx
mov [0],al
3. 字的傳送
上面通過(guò) mov 指令在寄存器和內(nèi)存之間進(jìn)行字節(jié)型數(shù)據(jù)的傳送例获。因?yàn)?8086CPU 是 16 位結(jié)構(gòu)汉额,有 16 根數(shù)據(jù)線,所以榨汤, 可以一次性傳送 16 位的數(shù)據(jù)蠕搜,也就是說(shuō)可以一次性傳送一個(gè)字。只要在 mov 指令中給出 16 位的寄存器就可以進(jìn)行 16 位數(shù)據(jù)的傳送了收壕。
指令樣板如下:
mov bx, 1000
mov ds,bx
mov ax,[0]
mov [0],cx
問(wèn)題 4-3:
內(nèi)存情況如圖 4-4 所示:
執(zhí)行如下命令后寄存器 ax, bx, cx 值各是多少妓灌?
mov ax,1000
mov ds,ax
mov ax,[0]
mov bx,[2]
mov cx,[1]
add bx,[1]
add cx,[2]
分析:
指令 | 執(zhí)行后寄存器內(nèi)容 | 指令說(shuō)明 |
---|---|---|
mov ax,1000 | ax=1000H | 向寄存器 ax 中送入內(nèi)容 1000 |
mov ds,ax | ds=1000H | 段地址寄存器內(nèi)容設(shè)置為 1000 |
mov ax,[0] | ax=1123H | 這里 ax 寄存器是 16 位,取內(nèi)存 10000 處 一個(gè)字型數(shù)據(jù) 1123H 送入 ax 中 |
mov bx,[2] | bx=6622H | bx 16 位寄存器蜜宪,取內(nèi)存 10002H 處一個(gè)字型數(shù)據(jù) 6622H 送入 bx 寄存器中 |
mov cx,[1] | cx=2211H | cx 16 位寄存器虫埂,取內(nèi)存 10001H 處一個(gè)字型數(shù)據(jù) 2211H 送入 bx 寄存器中 |
add bx,[1] | bx=8833H | bx 內(nèi)容為 6622H 取內(nèi)存 10001H 中 2211H 執(zhí)行 6622H + 2211H = 8833H,將計(jì)算結(jié)果送入 bx 寄存器中 |
add cx,[2] | cx=8833H | cx 內(nèi)容 2211H 取出內(nèi)存 10002H 中 6622H 相加得出 8833H 送入 cx 寄存器中 |
具體操作:
通過(guò) e 命令已經(jīng)將內(nèi)存數(shù)據(jù)寫入圃验,然后向內(nèi)存中寫入上述指令掉伏,通過(guò)修改 cs:ip ,執(zhí)行指令
問(wèn)題 4-4:
內(nèi)存情況如圖 4-5:
執(zhí)行下面命令后內(nèi)存中的值:
mov ax,1000
mov ds,ax
mov ax,11316(十進(jìn)制)
mov [0],ax
mov bx,[0]
sub bx,[2]
mov [2],bx
指令 | 執(zhí)行后寄存器內(nèi)容 | 指令說(shuō)明 |
---|---|---|
mov ax,1000 | ax=1000H | 向寄存器 ax 中送入內(nèi)容 1000 |
mov ds,ax | ds=1000H | 段地址寄存器內(nèi)容設(shè)置為 1000 |
mov ax,11316 | ax=2C34H | 11316 的十六進(jìn)制 2C34H |
mov [0],ax | 內(nèi)存 10000H:34 10001H:2C | ax 中低位送入 10000H,高位送入 10001H |
mov bx,[0] | bx=2C34 | 取出內(nèi)存 10000H 出字型數(shù)據(jù) 2C34 放入 bx 寄存器 |
sub bx,[2] | bx=1B12 | 2C34H - 1122H=1B12H |
mov [2],bx | 10003H:1B 10002:12 其他不變 | 寄存器 bx 中 1B12H 送入內(nèi)存 |
4 mov add sub 指令
前面我們用到的 mov 指令形式有以下幾種:
mov 寄存器澳窑,數(shù)據(jù)
mov 寄存器斧散,寄存器
mov 寄存器,內(nèi)存單元
mov 內(nèi)存單元照捡,寄存器
mov 段寄存器颅湘,寄存器
基于前面使用的指令,猜想:
1) mov 寄存器栗精,段寄存器(驗(yàn)證寄存器和段寄存器之間是否有相反的通路)
通過(guò)上面執(zhí)行 mov ax,ds 可以看到詞條命令是合法的, 所以寄存器和段寄存器之間是相互通路的闯参。
2)mov 內(nèi)存單元,段寄存器
mov ax,1000H
mov ds,ax
mov [0],cs
操作如下:CS 中內(nèi)容 073F悲立,將其放入的 10000H 內(nèi)存單元內(nèi)鹿寨,這里需要注意的是 CS 是一個(gè) 16 位寄存器,所以需要兩個(gè)內(nèi)存單元 存放其中去除的數(shù)據(jù)薪夕,低地址存放 3F 高地址存放 07:
3)mov 段寄存器,內(nèi)存單元
mov ax, 1000H
mov ds,ax
mov ds,[0]
將內(nèi)存單元中 10000H 字型數(shù)據(jù)送入 DS 寄存器中:
下面這些以供練習(xí):
add 寄存器, 數(shù)據(jù)
add 寄存器馏慨,寄存器
add 寄存器埂淮,內(nèi)存單元
add 內(nèi)存單元,寄存器
sub 寄存器写隶,數(shù)據(jù)
sub 寄存器倔撞,寄存器
sub 寄存器,內(nèi)存單元
sub 內(nèi)存單元慕趴,寄存器
5 數(shù)據(jù)段
對(duì)于 8086PC 機(jī)痪蝇,在編程時(shí),可以根據(jù)需要冕房,將一組內(nèi)存單元定義為一個(gè)端躏啰。我們可以將一組產(chǎn)孤單為N(N <= 64KB) 地址連續(xù),起始地址為 16 的倍數(shù)的內(nèi)存單元當(dāng)作專門存儲(chǔ)數(shù)據(jù)的內(nèi)存空間耙册,從而定義了一個(gè)數(shù)據(jù)段给僵。
比如 123B0H ~ 123B9H 這段內(nèi)存空間來(lái)存放數(shù)據(jù),我們就可以認(rèn)為觅玻, 123B0H ~ 123B9H 這段內(nèi)存是一個(gè)數(shù)據(jù)段想际,它的段地址為 123BH,長(zhǎng)度為 10 個(gè)字節(jié)溪厘。
那么胡本,如何訪問(wèn)數(shù)據(jù)段中的數(shù)據(jù)呢?
將一段內(nèi)存當(dāng)作數(shù)據(jù)段畸悬,是我們?cè)诰幊虝r(shí)的一種安排侧甫,可以在具體操作的時(shí)候,用 ds 寄存器存放數(shù)據(jù)段的段地址蹋宦,再根據(jù)需要披粟,用相關(guān)指令訪問(wèn)數(shù)據(jù)段中的具體單元。
比如冷冗,將 123B0H ~ 123B9H 的內(nèi)存單元定義為數(shù)據(jù)段∈靥耄現(xiàn)在要累加這個(gè)數(shù)據(jù)段中的前 3 個(gè)單元中的數(shù)據(jù),代碼如下:
mov ax, 123bH
mov ds,ax
mov al,0
add al,[0]
add al,[1]
add al,[2]
這里需要強(qiáng)調(diào)一點(diǎn)蒿辙,是前3 單元內(nèi)容拇泛,內(nèi)存單元每個(gè)大小為 8 位(即一個(gè)字節(jié)),所以只需要的是 8 位寄存器思灌,當(dāng)然這里可以自行驗(yàn)證俺叭,當(dāng)?shù)匚患拇嫫鲾?shù)據(jù)超過(guò)了之后是否會(huì)進(jìn)位到高位寄存器。
問(wèn)題 4-5
寫幾條指令泰偿,累加數(shù)據(jù)段中前 3 個(gè)字型數(shù)據(jù):
mov ax,123BH
mov ds,ax
mov ax,0
mov ax,[0]
mov ax,[2]
mov ax,[4]
小結(jié):
1) 字在內(nèi)存中存儲(chǔ)時(shí)熄守,要用兩個(gè)地址連續(xù)的內(nèi)存單元來(lái)存放,字的低位字節(jié)存放在低地址單元中,高位字節(jié)存放在高地址單元中裕照;
2)用 mov 指令訪問(wèn)內(nèi)存單元攒发,可以再 mov 指令中只給出單元的偏移地址,此時(shí)晋南,段地址默認(rèn)在 DS 寄存器中晨继;
3)[address] 表示一個(gè)偏移地址為 address 的內(nèi)存單元;
4)在內(nèi)存和寄存器之間傳送字型數(shù)據(jù)時(shí)搬俊,高地址單元和高 8 位寄存器、低地址單元和低 8 位寄存器相互對(duì)應(yīng)蜒茄;
5)mov唉擂、add、sub 是具有兩個(gè)操作對(duì)象的指令檀葛。 jmp 是具有一個(gè)操作對(duì)象的指令玩祟;
6)可以根據(jù)自己的推測(cè),在 Debug 中實(shí)驗(yàn)指令的新格式
6 棧
這了對(duì)棧的研究限于:棧是一種具有特殊訪問(wèn)方式的存儲(chǔ)空間(LIFO)屿聋。
這里通過(guò)盒子放書的操作過(guò)程來(lái)描述棧的操作空扎,如圖 4-6 所示:
現(xiàn)在,一次只允許取一本润讥,如何將 3 本書從盒子中取出转锈?
顯然,必須從盒子最上邊取楚殿,這樣取出的順序就是: 《軟件工程》《C 語(yǔ)言》《高等數(shù)學(xué)》撮慨,和放入的順序正好相反,如圖 4-7 所示:
從程序化角度脆粥,我們通過(guò)綠色箭頭做一個(gè)標(biāo)記砌溺,這個(gè)標(biāo)記一直指著盒子最頂端的書籍。
總結(jié):
如果說(shuō)盒子就是一個(gè)棧变隔,那么這個(gè)棧有兩個(gè)操作规伐,分別是入棧和出棧。
入棧匣缘,就是將一個(gè)新的元素放到棧頂猖闪,出棧就是從棧頂取出一個(gè)元素。棧頂?shù)脑乜偸亲詈笕霔7趸В绻鰲5脑捪舫瑮m斣匾彩堑谝粋€(gè)被取出(LIFO)。
7 CPU 提供的棧機(jī)制
現(xiàn)在的 CPU 中都有棧的設(shè)計(jì)夏哭, 8086CPU 也不例外检柬。8086CPU 提供相關(guān)的指令來(lái)以棧的方式訪問(wèn)內(nèi)存空間。這意味著,在基于 8086CPU 編程的時(shí)候何址,可以將一段內(nèi)存當(dāng)做棧來(lái)使用里逆。
8086CPU 提供入棧和出棧指令,最基本的兩個(gè)是 PUSH 和 POP 用爪,比如原押, push ax 表示將寄存器 ax 中的數(shù)據(jù)送入到棧中, pop ax 表示從棧頂取出數(shù)據(jù)送入到 ax偎血。 8086CPU 的入棧和出棧操作都是以字為單位進(jìn)行诸衔。
舉例說(shuō)明,我們可以將 10000H~1000FH這段內(nèi)存當(dāng)做棧來(lái)使用颇玷,如圖 4-8 所示:
指令如下:
mov ax,0123H
push ax
mov bx,2266H
push bx
mov cx,1122H
push cx
pop ax
pop bx
pop cx
注意笨农,字型數(shù)據(jù)用兩個(gè)單元存放,高地址單元存放高 8 位帖渠,低地址單元存放低 8 位谒亦。
如圖 4-8 所示,有兩個(gè)疑惑在這里說(shuō)明一下:
第一點(diǎn)疑惑空郊,上面我們將內(nèi)存的 10000H~1000FH 這段作為棧來(lái)來(lái)使用份招,然后執(zhí)行 push 和 pop 指令。但是狞甚,CPU 是如何知道 10000H~1000FH 這段空間被當(dāng)作棧來(lái)使用的呢 锁摔?
第二點(diǎn)疑惑,push ax 入愧, pop ax 等指令執(zhí)行的時(shí)候鄙漏,要訪問(wèn)棧頂單元,那么這兩個(gè)指令又是如何知道那個(gè)內(nèi)存單元是棧頂單元呢 棺蛛?
這里怔蚌,我們回顧下,CPU 如何知道當(dāng)前要執(zhí)行指令所在的位置呢 旁赊?
在前面的操作中桦踊,我們也已經(jīng)知道,那就是 CS 和 IP 兩個(gè)寄存器存放著當(dāng)前指令的段地址和偏移地址终畅。
現(xiàn)在的問(wèn)題是: CPU 如何知道棧頂位置 籍胯?
顯然,也應(yīng)該有相應(yīng)的寄存器來(lái)存放棧頂?shù)刂罚?806CPU 中离福,有兩個(gè)寄存器杖狼,段寄存器 SS 和 SP,棧頂段地址存放在 SS 中妖爷,偏移地址存放在 SP 中蝶涩。
在任意時(shí)候, SP:IP指向棧頂元素
push 和 pop 指令執(zhí)行時(shí),CPU 從 SS 和 SP 中得到棧頂?shù)牡刂贰?br> 現(xiàn)在绿聘,我們可以完整地描述 push 和 pop 指令的功能了嗽上,例如 push ax。
push ax 的執(zhí)行熄攘,由一下兩步完成:
(1)SP=SP-2兽愤, SS:SP 指向當(dāng)前棧頂前面的單元,以當(dāng)前棧頂前面的單元為新的棧頂挪圾;
(2)將 ax 中的內(nèi)容送入 SS:SP 指向的內(nèi)存單元處浅萧,SS:SP此時(shí)指向新棧頂。
如圖 4-8 所示:
從圖中哲思,可以看出惯殊,8086CPU中入棧時(shí),棧頂從高地址向低地址方向增長(zhǎng)也殖。
問(wèn)題 4-6
如果將 10000H ~ 1000FH 這段地址當(dāng)做棧,初始狀態(tài)是空棧务热,此時(shí) SS = 1000H忆嗜,那么 SP=?
分析
SP = 0010H崎岂,如圖 4-8 所示捆毫,
將 10000H ~ 1000FH 這段空間當(dāng)做棧段,SS = 1000H冲甘,椉保空間大小為 16 字節(jié),棧最底部的字單元地址為 1000:000E江醇。 任意時(shí)刻濒憋,SS:SP 指向棧頂,當(dāng)棧中只有一個(gè)元素的時(shí)候陶夜,SS=10000H凛驮, SP=1000EH。
棧為空的話条辟,也就是說(shuō)黔夭,相當(dāng)于棧中唯一的元素出棧,出棧后羽嫡,SP=SP+2本姥,SP 原來(lái)為 000EH,加 2 后杭棵,SP = 10H婚惫,所以當(dāng)棧空的時(shí)候,SS=1000H辰妙,SP=10H鹰祸。
換一個(gè)角度看,任意時(shí)刻密浑,SS:SP 指向棧頂元素蛙婴,當(dāng)棧為空的時(shí)候,棧中沒(méi)有元素尔破,也就不存在棧頂元素街图,所以 SS:SP 指向棧最底部單元下面的單元,該單元的偏移地址為最底部字單元偏移地址 +2 懒构,棧最底部的字單元地址為 1000:000E, 所以棽图茫空時(shí), SP=0010H胆剧。
接下來(lái)絮姆,看一下 pop 操作:
pop ax
pop ax 和 push ax 正好相反,由以下兩步組成:
(1)將 SS:SP 指向的內(nèi)存單元處的數(shù)據(jù)送入 ax 中秩霍;
(2)SP=SP+2,SS:SP指向當(dāng)前棧頂下面的一個(gè)單元篙悯,以當(dāng)前棧頂下面的單元為新的棧頂。
如下圖 4-10 所示铃绒, POP AX 的過(guò)程:
這里需要注意第三步鸽照,盡管當(dāng)前棧指針指向 1000E H 但是內(nèi)存單元 1000DH 和 1000CH 中的數(shù)據(jù)任然存在,只不過(guò)不在棧中颠悬,直到下一次 PUSH 操作將其覆蓋為止矮燎。
8 棧頂越界問(wèn)題
這一小節(jié),介紹越界問(wèn)題赔癌。
比如诞外,我們將內(nèi)存地址空間 10010H ~ 1001FH 作為棧空間灾票,該椙城牵空間容量為 16 字節(jié)(8個(gè)字)。
初始狀態(tài)棧為空靖苇, SS=1000H,SP=0020H班缰,SS:SP 指向 10020H贤壁。
ax=0123H
執(zhí)行 8 次 PUSH AX 操作,向棧中壓入 8 個(gè)字埠忘,棧滿脾拆,SS=1000H SP=0010, SS:SP 指向 10010H
執(zhí)行 8 次 PUSH AX 操作之后,棧滿名船,如果在執(zhí)行一次 PUSH AX,那么 SP=SP-2绰上,SP=000E, SP=1000E
此時(shí),PUSH 操作已經(jīng)超過(guò)了椙眨空間蜈块,將棧外空間數(shù)據(jù)覆蓋。
POP 操作類似迷扇。
主要操作細(xì)節(jié)是:
通過(guò) -a 將命令寫入當(dāng)前指令寄存器指向的內(nèi)存地址空間百揭,然后,通過(guò) -r 指令修改寄存器內(nèi)容蜓席,包括棧寄存器 SP 和 SS 以及數(shù)據(jù)寄存器 AX 內(nèi)容器一。
這里需要注意,POP 和 PUSH 都會(huì)出現(xiàn)越界厨内,但是 8086CPU 并沒(méi)有機(jī)制保證我們不越界祈秕,所以在編程的時(shí)候需要自己操作棧頂越界的問(wèn)題。
9 push 雏胃、pop 指令
前面我們一直在使用 PUSH AX 和 POP AX 這兩條指令踢步,他們可以將數(shù)據(jù)在內(nèi)存和寄存器之間進(jìn)行傳送。(棾蟛簦空間是內(nèi)存的一部分,它只是一段可以以一種特殊方式進(jìn)行訪問(wèn)的內(nèi)存空間)
除此之外述雾, PUSH 和 POP 這兩條指令的目標(biāo)地址還可以是段寄存器或者內(nèi)存空間街州。
練習(xí) 1
將 10000H~1000F 這段空間當(dāng)做棧,初始狀態(tài)棽C希空唆缴,將 ax,bx黍翎,ds 中的數(shù)據(jù)送入棧面徽。
-
設(shè)置棧寄存器
SS=1000H SP=0010 SS:SP=10010
-
將數(shù)據(jù)送入寄存器
ax=1234H
bx=5678H
ds=9ABCH
-
將指令 push ax ,push bx匣掸, push ds 寫入內(nèi)存單元
-
執(zhí)行第 3 步寫入的指令
執(zhí)行 PUSH 操作
練習(xí) 2
編程:
(1) 將 10000H~1000FH 這段空間當(dāng)作棧趟紊,初始狀態(tài)是空的;
(2)設(shè)置 AX=001AH 碰酝, BX=001BH霎匈;
(3)將 AX、BX 中的數(shù)據(jù)入棧送爸;
(4)然后將 AX铛嘱、BX 清零暖释;
(5)從棧中恢復(fù) AX、BX 原來(lái)的內(nèi)容墨吓。
解析:
首先設(shè)置棧寄存器值
SS=1000H SP=0010H SS:SP=10010H設(shè)置 AX BX 的值
AX=001AH
BX=001BH入棧球匕,執(zhí)行 PUSH AX 和 PUSH BX 操作
a 寫入 push ax 和 push bx
t 執(zhí)行命令清零
ax=0000H
bx=0000H執(zhí)行 POP BX POP AX 操作