hehe

王爽匯編全書知識點大綱


第一章 基礎(chǔ)知識

  • 機(jī)器語言

機(jī)器語言是機(jī)器指令的集合,電子計算機(jī)的機(jī)器指令是一系列二進(jìn)制數(shù)字.計算機(jī)將之轉(zhuǎn)換為一系列高低電平脈沖信號來驅(qū)動硬件工作的.

  • 匯編語言的產(chǎn)生

由于機(jī)器語言指令都是由01組成,難以編寫,記憶和維護(hù)程序.所以匯編語言為了解決這一問題產(chǎn)生.匯編語言又稱為機(jī)器語言的助記符

  • 匯編語言的組成

匯編指令:有對應(yīng)的機(jī)器碼.機(jī)器碼的助記符

偽指令:沒有對應(yīng)的機(jī)器碼,由編譯器執(zhí)行,計算機(jī)并不執(zhí)行.

其他符號:如+,-,*,/等,由編譯器識別,沒有對應(yīng)的機(jī)器碼

  • 存儲器

  • 相當(dāng)于大腦,程序指令和數(shù)據(jù)在存儲器中都是以二進(jìn)制數(shù)據(jù)形式存放,沒有什么區(qū)別.且內(nèi)存是動態(tài)存儲數(shù)據(jù)的,程序或文件從磁盤加載到內(nèi)存才能由cpu直接讀取.斷電后,內(nèi)存中的數(shù)據(jù)就消失了.磁盤才是永久存儲數(shù)據(jù)的地方.

  • 存儲單元從0開始編號.能存儲一個8位二進(jìn)制數(shù)的單元,稱為存儲單元.為一個byte.大小,單位B. 位的單位為bit.向上為kb,mb,GB,TB,PB

  • cpu對存儲器的讀寫

  • 必要的信息交互

(1). 存儲單元的地址(地址信息),地址總線(cpu要從存儲器中讀取數(shù)據(jù),首先要要確認(rèn),某個存儲單元的地址.)

(2).器件的選擇,讀或?qū)懙拿?控制信息)控制總線(另外計算器中不只有存儲器一種器件,其它器件,也有存儲器.要確定從什么器件讀取.)

(3).讀或?qū)懙臄?shù)據(jù)(數(shù)據(jù)信息),數(shù)據(jù)總線.

總線與信息傳送 : 電子計算機(jī)能處理,傳輸?shù)男畔⒍际请娦盘?電信號當(dāng)然通過導(dǎo)線傳送,也就是總線(數(shù)根導(dǎo)線的集合).

讀取例子:Mov Ax,[3]

CPU通過地址線將地址信息3發(fā)出cpu通過控制總線發(fā)出讀命令,并選中存儲器芯片,并通知他,將要從中取數(shù)據(jù),存儲器將3號單元中的數(shù)據(jù)8通過數(shù)據(jù)線送入cpu

  • 三大總線

  • 地址總線

地址總線:8根,表示能尋址0-1023的內(nèi)存單元.能尋址2^8個內(nèi)存單元,代表了cpu的尋址范圍

  • 數(shù)據(jù)總線

假如數(shù)據(jù)總線有8根,那么每次只能傳送1B數(shù)據(jù).每次只能傳送一個8位數(shù).

  • 控制總線

假如控制總線位有8根,那么有2^8種控制方式,控制總線的寬度決定了CPU對外部器件的控制能力.

  • 內(nèi)存地址空間

  • 每種器件cpu都通過總線將其連接,cpu在操控它們的時候,都把它們當(dāng)成是內(nèi)存來對待.(正如linux把每個硬件都當(dāng)成文件來對待),操作顯示器就是操作顯存,顯存就可以當(dāng)文件一樣進(jìn)行讀寫操作.cpu操作硬件實際上就是操作硬件的內(nèi)存或端口

  • 0-7fffh的32kb空間為主隨機(jī)存儲器的地址空間.地址8000h-9fffh的8kb空間為顯存地址空間A000h~ffffh的24kb空間為各個rom的地址空間.(寫入顯存地址空間,就會顯示在顯示器上,寫入只讀rom地址空間,那么沒有任何效果,我們基于一個計算機(jī)硬件系統(tǒng)編程的時候,必須知道這個系統(tǒng)中的內(nèi)存地址空間分配情況).

  • BIOS有一個只讀room,是硬件和操作系統(tǒng)的接口.

第二章 寄存器

  • cpu的基本結(jié)構(gòu)

  • 運(yùn)算器:運(yùn)算器進(jìn)行信息處理

  • 寄存器:寄存器進(jìn)行信息存儲

  • 控制器:控制器控制各種器件進(jìn)行工作

  • 內(nèi)部總線:用來連接cpu內(nèi)部各種元器件的導(dǎo)線集合

  • 寄存器:AX,BX,CX,DX, SI,DI,SP,BP,IP, CS,SS,DS,ES, PSW

  • 通用寄存器

為了和上一代cpu兼容可以拆分16位通用寄存器,拆分為兩個8位寄存器.從右向左,以0開始編號.

  • AX可拆分為AH和AL

  • BX可拆分為BH和BL

  • CX可拆分為CH和CL

  • DX可拆分為DH和DL

  • 字的存儲和數(shù)制表示

  • 字在寄存器中的存儲:高8位放在寄存器的高8位中,低8位放在寄存器的低8位中

  • 字在內(nèi)存中的存儲:低位存儲在低地址中,高位存儲在高地址中.稱為小尾存儲.

  • 數(shù)制的表示:源代碼中默認(rèn)數(shù)制是十進(jìn)制,在數(shù)字后面添加h表示16進(jìn)制,如果16進(jìn)制最高位為字符,那么必須在前面添0, 如果數(shù)字后面加b后綴表示二進(jìn)制數(shù)字. 特別注意,在debug中數(shù)制默認(rèn)是16進(jìn)制.

  • 幾條匯編指令

  • 匯編指令默認(rèn)不區(qū)分大小寫

  • 假設(shè)ax和bx中的值為8226h,add ax,bx執(zhí)行后,相加的結(jié)果為1044ch,但是ax存儲不下,最后ax中的值為044ch

  • 假設(shè)ax中的值為00c5h,add al,85h執(zhí)行結(jié)果為158h,al存儲不下會設(shè)置標(biāo)志位.千萬不要認(rèn)為高位進(jìn)位會存儲在ah中,這是錯誤的想法,最后ax中的結(jié)果為0058h.

  • 下面的指令是錯誤指令:

mov ax,bl //兩個寄存器尺寸不一致

mov bh,ax //兩個寄存器尺寸大小不一致

mov al 20000 //20000在al中不能存儲

add al 100H //100h超過al中存儲的最大范圍

  • 計算2^4:

Mov ax,2

ADD AX,AX

ADD AX,AX

ADD AX,AX

  • 8086物理地址

  • 內(nèi)存空間是一個線性空間.每一個內(nèi)存單元在這個空間中都有唯一的地址,我們將這個唯一的地址稱為物理地址.

  • 16位機(jī)的含義:

  • 運(yùn)算器一次最多處理 16 位的數(shù)據(jù)

  • 寄存器最大寬度為 16 位

  • 寄存器和運(yùn)算器之間通路為 16 位,即數(shù)據(jù)總線 16 條

  • 物理地址的計算:為了用16位地址尋址更多的內(nèi)存,8086采取用連個16位寄存器合成一個20位地址,即

段寄存器中的地址*16+16位偏移地址

  • 一個段的起始地址必然是16的倍數(shù)

  • 因為偏移寄存器只有16位大小,所以給定一個段,它最大能在當(dāng)前段尋址64kb

  • 尋址過程:段地址和偏移地址通過內(nèi)部總線送入一個稱為地址加法器的部件,地址加法器通過內(nèi)部總線將20位物理地址送入輸入輸出控制電路.輸入輸出控制電路將20位物理地址送上地址總線.20位物理地址總線傳送到存儲器.

  • 一個地址可以用不同的段形式表示.

  • CS和IP

  • 段寄存器:CS,DS,ES,SS

  • CS位代碼段寄存器,IP位代碼偏移地址寄存器,cpu把任何時刻cs和ip指向的地址處的數(shù)據(jù)當(dāng)做指令執(zhí)行.

  • 指令的讀取和執(zhí)行:

  • 假設(shè)地址2000:0~2000:2中存儲著指令mov ax,123h

  • 初始狀態(tài)cs=2000h,ip=0,將從內(nèi)存2000h:0中讀取指令執(zhí)行

  • 將CS和IP的值送上地址加法器合成一個20位的物理地址

  • 地址加法器將物理地址送入輸入輸出電路

  • 輸入輸出電路將物理地址20000h送上地址總線

  • 從地址20000h中讀取數(shù)據(jù)通過數(shù)據(jù)總線送入cpu

  • 輸入輸出電路將指令mov ax,123h送入指令緩沖器

  • 讀取一條指令后ip的值自動增加,指向可以讀取的下一條指令

  • 執(zhí)行控制器執(zhí)行指令mov ax,123h

  • 然后重復(fù)上面的步驟

  • 8086cpu加電啟動或復(fù)位后,cs和ip被設(shè)置為cs=ffffh,ip=0000h,cpu從內(nèi)存FFFF0h單元中讀取指令并執(zhí)行.

  • 修改cs和ip的指令:

  • 通過修改cs和ip的指向,起到控制cpu執(zhí)行流程和跳轉(zhuǎn)等功能.在debug中可以通過mov指令修改cs的值,但是不能用mov修改ip的值

  • 在cpu中程序員能夠用指令讀寫的部件只有寄存器

  • mov指令不能用于設(shè)置cs:ip的值.原因很簡單,因為沒有這個功能.但是debug中可以用mov cs,xxx

  • 想同時修改 CS,IP

jmp 1000:0 則 CS=1000H悬嗓,IP=0000H //這條指令只在debug中有效

僅修改 IP 的內(nèi)容

jmp 某一合法寄存器 //在源代碼中也有效

  • debug調(diào)試指令

  • 用 R(register) 命令查看或改變 cpu 寄存器內(nèi)容

  • r ax/其它寄存器 功能:修改 ax 寄存器內(nèi)容

  • 直接r, 查看各個寄存器的值.

  • 用 D(dump)命令查看內(nèi)存中內(nèi)容

  • d 1000:0 會顯示10000:0地址開始的128個內(nèi)存單元的內(nèi)容

  • D 段地址:開始偏移地址 結(jié)束偏移地址 可以查看指定內(nèi)存單元的內(nèi)容例子如下:

  • D 1000:0 f (1000:0 ~ 1000:f內(nèi)存單元的數(shù)據(jù)) 再次輸入D會把后續(xù)的128個內(nèi)存單元內(nèi)容顯示出來.

  • 用 E (enter)命令改寫內(nèi)存中的內(nèi)容

  • 采用“e 起始段地址:偏移地址 數(shù)據(jù) 數(shù)據(jù) 數(shù)據(jù)..." e 1000:0 0 1 2 3 4 5 6 7 寫機(jī)器碼.這是一次性輸入

  • 用一個一個的輸入方式,改寫內(nèi)存的內(nèi)容 (按空格鍵陸續(xù)輸入,敲回車結(jié)束輸入.) 例如 e 1000:0,以向內(nèi)存中寫入字符 e 1000:0 1 'a' 2 'b' 3 'c' 寫機(jī)器碼和字符.

注:e命令寫進(jìn)去的機(jī)器碼數(shù)值16進(jìn)制形式,所以數(shù)字不能超過兩位十六位數(shù)字,eg:111這是錯誤的(因為debug中默認(rèn)是16進(jìn)制數(shù)制).

  • 用 U(unassemble) 查看內(nèi)存中機(jī)器碼含義娃胆,用 T 執(zhí)行cs:ip指向的指令.

  • U 段地址:偏移地址

  • 查看指定地址間的匯編指令:U 段地址:偏移地址 結(jié)束地址

  • 用 A(assemble) 以匯編指令形式在內(nèi)存中寫入機(jī)器指令. A 段地址:偏移地址

  • 用g(go) 命令跳到某指令,g 地址

eg:g 0012(表示從當(dāng)前cs:ip指向的指令執(zhí)行,一直到(ip) = 0012為止.) 用 t(trace) 命令單步執(zhí)行 用 p (proceed)命令跳躍循環(huán)

  • q退出debug

  • dosbox中可以按alt+enter鍵實現(xiàn)全屏.

  • debug界面認(rèn)識

  • 習(xí)題講解:下面的代碼幾次修改IP的值

mov ax,bx

sub ax,ax

jmp ax

答:一共4次,第一次:讀取完mov ax,bx后.第二次:讀取完sub ax,bx后.第三次:讀取完jmp ax后.第四次:執(zhí)行完jmp ax后.

第三章 寄存器內(nèi)存訪問

  • 字在內(nèi)存中的存儲

  • 低位字節(jié)存放在低地址單元中,高位字節(jié)存放在高地址單元中.

  • 字單元:兩個字節(jié)聯(lián)合起來的16位.存儲單元.起始地址為N的字單元簡稱為N地址字單元

  • DS和[ADRESS]訪問內(nèi)存單元

  • ds寄存器用來存放要訪問的內(nèi)存單元的段地址

  • 8086硬件設(shè)計的問題,不能將立即數(shù)直接用mov指令傳送到段寄存器中

  • 在源代碼中使用[idata]時,[idata]會被當(dāng)成idata.

調(diào)試的時候,[idata]才會被翻譯成內(nèi)存單元.源代碼中需要使用[bx/si/di..]等

表示內(nèi)存單元.也可以使用段前綴, 段寄存器 : [idata]

  • 字的傳送

  • 只要在mov指令中給出的寄存器是16位,就會對字進(jìn)行操作.

  • 也可以用尺寸指針指明要操作的內(nèi)存單元大小,byte ptr [],word ptr [],dword ptr[]

  • mov/add/sub指令詳解

  • mov指令有以下幾種格式:


mov 寄存器,數(shù)據(jù)

mov 寄存器,寄存器

mov 寄存器,內(nèi)存單元

mov 內(nèi)存單元,寄存器

mov 段寄存器,寄存器

mov 寄存器,段寄存器 //這個是自己實驗添加的

mov 段寄存器,內(nèi)存單元//這個是自己實驗添加的

mov 內(nèi)存單元,段寄存器//這個是自己實驗添加的

注意事項:

  1. 從這幾種格式可以看出,操作數(shù)不能同時為段寄存器
  1. 也不能同時為內(nèi)存操作數(shù).
  1. 不能將立即數(shù)直接送入段寄存器.
  1. 立即數(shù)只能放在右邊,如果此時左邊操作數(shù)為內(nèi)存單元,需要指明內(nèi)存單元尺寸
  1. 操作數(shù)不能出現(xiàn)ip寄存器
  • add指令有以下幾種格式:

add 寄存器,數(shù)據(jù)

add 寄存器,寄存器

add 寄存器,內(nèi)存單元

add 內(nèi)存單元,寄存器

add byte/word/... ptr 內(nèi)存單元,數(shù)據(jù)

注意事項:

  1. add指令中不能出現(xiàn)段寄存器操作數(shù)
  1. add中操作數(shù)不能同時為內(nèi)存單元
  1. 第一個操作數(shù)必須是寄存器或者內(nèi)存單元
  1. add指令中也不能出現(xiàn)ip寄存器
  • sub指令,格式和使用方式同add指令

  • 數(shù)據(jù)段

  • 我們可以將一組已知起始地址的內(nèi)存單元定義為數(shù)據(jù)段,該段<= 64kb

  • 然后將ds設(shè)置為起始地址,然后該地址開始的段就可以當(dāng)做數(shù)據(jù)段使用

  • 同理可以設(shè)置ss:sp的指向,來構(gòu)造棧段

  • 代碼段是通過,end 標(biāo)號 指明起始地址(標(biāo)號就是代碼段開始處)

  • 后進(jìn)先出數(shù)據(jù)結(jié)構(gòu),最初棧指針指向高地址,越壓棧,sp寄存器指針越往低地址移動.

  • 通過ss:sp指定和初始化棧.

  • push和pop指令出棧和入棧

  • push 寄存器/內(nèi)存單元/段寄存器 : sp=sp-2 mov (sp),(寄存器/內(nèi)存單元/段寄存器)

  • pop 寄存器/內(nèi)存單元/段寄存器: mov (寄存器/內(nèi)存單元/段寄存器),(sp) sp=sp+2

  • 注意事項:

操作數(shù)不能是ip寄存器,棧每次操作一個字

  • 椶认瑁可以超界,且沒有任何保護(hù)機(jī)制

  • 棧環(huán)繞問題

如果將10000H~1FFFFH這段空間當(dāng)做棧段,初始狀態(tài)是空的,此時ss=1000h,sp=?

答:sp=0,因為此時會發(fā)生棧環(huán)繞問題,FFFF的底端無法尋址,所以就會循環(huán)跑到另一頭0上面去.,此時壓棧會發(fā)生,sp=0-2=0FFFEH

  • 編程例子:

編程:將10000h~1000Fh這段空間當(dāng)做棧,初始狀態(tài)是空的,設(shè)置ax=001ah,bx=001bh,將ax,bx入棧,然后將ax,bx清零,從棧中恢復(fù)ax,bx的值.

解答:


mov ax,1000h

mov ss,ax

mov sp,10h

mov ax,001ah

mov bx,001bh

push ax

push bx

sub ax,ax

sub bx,bx

pop bx

pop ax

利用棧交換ax,bx內(nèi)容


push ax

push bx

pop ax

pop bx

....

  • 實驗2

  • 可以在調(diào)試命令中需要段地址的地方,使用段寄存器.例子如下:

  • d 1000:0 會將段地址1000送入ds中.

  • e ds:0 0 1 2 3 4

  • u cs:0 ;以匯編指令形式,顯示當(dāng)前代碼

  • a ds:0

  • ss:sp的設(shè)置指令應(yīng)該放在一起緊挨著,單步中斷并不會中斷,這兩條 指令會連續(xù)執(zhí)行,因為中斷也設(shè)計壓棧操作,那么假設(shè)如果在sp還未設(shè)置時,發(fā)生了中斷,那么中斷的壓棧操作將會壓入不正確的棧頂,緊接著又設(shè)置了新的sp值,那么程序就不會正確運(yùn)行.

第4章 第一個程序

  • 源程序到可執(zhí)行程序

  • 源程序文本文件-->編譯鏈接--->生成可執(zhí)行程序

  • 可執(zhí)行程序包含從源程序中翻譯過來的機(jī)器碼和數(shù)據(jù),還有相關(guān)的描述信息(比如,程序有多大,要占用多少內(nèi)存空間等)

  • 操作系統(tǒng)根據(jù)可執(zhí)行文件的描述信息,將可執(zhí)行文件中的機(jī)器碼和數(shù)據(jù)加載入內(nèi)存,并進(jìn)行相關(guān)的初始化,并進(jìn)行相關(guān)的初始化(比如設(shè)置CS:IP指向第一條指令),然后cpu執(zhí)行程序.

  • 如果不用end指明程序入口,那么編譯成程序時,cpu會自動將cs,ip指向改程序數(shù)據(jù)開頭.如果指定了標(biāo)號,那么cpu會將cs和ip指向標(biāo)號地址處.

  • 源程序


assume cs:code

code segment

mov ax,0123h

mov bx,0456h

add ax,bx

add ax,ax

mov ax, 4c00h

int 21h

code ends

end

  • xxx segment ....xxx ends偽指令是定義一個段.標(biāo)號就是偏移地址,不需要用offset獲取

  • end偽指令 : 表示結(jié)束一個匯編源程序的編譯,end 后面可以接一個標(biāo)號來指明可執(zhí)行代碼入口.

  • assume偽指令 : 它假設(shè)程序的某個段寄存器與某個段標(biāo)號相關(guān)聯(lián).通過這種關(guān)聯(lián),在需要的情況下,編譯程序可以將段寄存器和某一個具體的段想聯(lián)系.

  • 程序返回 : mov ax,4c00h int 21h程序返回.告訴運(yùn)行本程序的程序,運(yùn)行結(jié)束后的結(jié)果狀態(tài).ah=4c,傳遞中斷子程序功能號,表示調(diào)用21中斷的4c號子程序. Al=0表示返回值為0.如果不正確返回

程序就會運(yùn)行不正常.

  • 鏈接

  • 當(dāng)源程序很大的時候,我們可以將源程序分成多個程序,然后編譯成多個obj文件.然后連接在一起,

  • 程序中調(diào)用了某個庫文件中子程序,需要將這個庫文件和程序生成的目標(biāo)文件連接到一起,生成一個可執(zhí)行文件.

  • 一個源程序編譯后,得到了存有機(jī)器碼的目標(biāo)文件,目標(biāo)文件中的有些內(nèi)容還不能直接生成可執(zhí)行文件.連接程序?qū)⑦@些內(nèi)容處理為最終可執(zhí)行信息.所在,在只有一個源程序文件,而又不需要調(diào)用某個庫中的子程序的情況下,也必須用連接程序?qū)δ繕?biāo)文件進(jìn)行處理,生成可執(zhí)行文件.

  • dos程序的加載流程

  • dos中直接運(yùn)行exe文件時,首先加載入內(nèi)存,設(shè)置cs:ip的入口(end指定的標(biāo)號處).

  • 找到一段起始地址為SA:0000(即起始地址的偏移地址為0)的容量足夠的空閑內(nèi)存區(qū)

  • 前256個字節(jié)中創(chuàng)建一個段前綴psp的數(shù)據(jù)區(qū),dos利用psp來和被加載程序進(jìn)行通信.ds首先初始化時,是指向psp數(shù)據(jù)區(qū)的.

  • 程序放在SA+10H:0地址處,CS:IP指向這里

  • 實驗3

  • 雜項知識:將程序加載入內(nèi)存執(zhí)行,cx存儲的是程序的長度

第五章 [bx]和loop

  • [bx]

  • 要完整描述一個內(nèi)存單元需要兩種信息:@內(nèi)存單元地址@內(nèi)存單元長度

  • 表示段地址在ds中,bx中存放的是該段的偏移地址.

  • Loop指令

  • (cx)=(cx) - 1

  • 判斷cx中的值是否為零,非零繼續(xù)循環(huán),零則退出循環(huán).

  • 循環(huán)例子程序:計算2^12次方


assume cs:code

code segment

mov ax,2

mov cx,11

s:

add ax,ax

loop s

mov ax, 4c00h

int 21h

code ends

end

例子2:計算123*236


assume cs:code

code segment

mov ax,0

mov cx,123

s:

add ax,236

loop s

mov ax, 4c00h

int 21h

code ends

end

  • inc/dec 寄存器或

  • inc/dec (byte /word/..) ptr [內(nèi)存單元]

  • 自增或自減指令

  • 雜項

  • 在匯編源程序中亚隙,數(shù)據(jù)不能以字母開頭需要在前面添加一個0.

  • 在 dos 下躬络,一般情況 0:200-0:2ff 空間中沒有系統(tǒng)或其他程序的數(shù)據(jù)或代碼

  • 遇到loop指令時,用p,可以跳過循環(huán).遇到int 21是也可以用p命令結(jié)束程序

  • g 地址偏移 ,直接跳轉(zhuǎn)到該地址處執(zhí)行

  • loop和bx 的聯(lián)合應(yīng)用

  • 計算ffff:0~ffff:b每個內(nèi)存單元中的數(shù)據(jù)相加的和,結(jié)果存儲在dx中


assume cs:code

code segment

mov ax,0ffffh

mov ds,ax

mov bx,0

mov dx,0

mov cx,12

mov ah,0

s:

mov al,[bx]

add dx,ax

inc bx

loop s

mov ax, 4c00h

int 21h

code ends

  • 段前綴

  • 可以在[idata]或[bx]前面加上cs,ds,es,ss等段前綴來指明段地址

  • cs/ds/es/ss : []

  • 段前綴的使用

  • 編程:將內(nèi)存ffff:0ffff:b單元的數(shù)據(jù)復(fù)制到0:200020b中


assume cs:code

code segment

mov ax,0ffffh

mov ds,ax

mov ax,0020h

mov es,ax

mov bx,0

mov cx,6

s:

mov ax,[bx]

mov es:[bx],ax

add bx,2

loop s

mov ax, 4c00h

int 21h

code ends

end

  • 實驗4 bx和loop的使用

  • 編程,向內(nèi)存0:200~0:23f依次傳送數(shù)據(jù)0-63(3fh)


assume cs:code

code segment

mov ax,0020h

mov ds,ax

mov bx,0

mov cx,64

s:

mov [bx],bl

inc bx

loop s

mov ax, 4c00h

int 21h

code ends

end

第六章 包含多個段的程序

  • 在代碼中使用數(shù)據(jù)

  • 程序獲得所需空間的方法有兩種

  • 是在程序加載的時候為程序分配

  • 是在程序運(yùn)行過程中向系統(tǒng)申請.我們只討論前者.因為后者屬于動態(tài)分配內(nèi)存.這兩種方式都是由操作系統(tǒng)分配.

  • 還有就是在dos時代,可以直接將數(shù)據(jù)送入內(nèi)存.當(dāng)數(shù)據(jù)有很多時,這種方法存儲明顯不現(xiàn)實

  • db定義字節(jié), dw定義字?jǐn)?shù)據(jù),dd定義雙字,dq8字節(jié),dt十字節(jié)

  • 程序框架


assume cs:code

code segment

start:

程序代碼

mov ax, 4c00h

int 21h

code ends

end start

end代表程序源代碼結(jié)束,并指明可執(zhí)行代碼入口地址.

如果指明入口地址,那么從程序的首地址開始執(zhí)行,不管起始地址處是否是可執(zhí)行代碼.

  • CPU根據(jù)什么設(shè)置CS:IP指向程序的第一條要執(zhí)行的指令?是由可執(zhí)行文件中的描述信息指明的.描述信息則主要是編譯,連接程序?qū)υ闯绦蛑邢嚓P(guān)偽指令進(jìn)行處理所得到的信息.

  • 即使我們用了類似Assume cs:code,ds:data這樣的偽指令,在執(zhí)行的時候,Cpu也不會把他們的段寄存器指向相應(yīng)的內(nèi)容,cpu在加載程序運(yùn)行把CS:IP指向我們Start入口處,我們在這里調(diào)整ss,ds等段寄存器的指向.

  • 在代碼中使用棧

  • 利用棧將程序中的數(shù)據(jù)逆序存放


assume cs:code

code segment

dw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h

dw 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0

start:

mov ax,cs

mov ss,ax

mov sp,30h

mov bx,0

mov cx,8

s:

push cs:[bx]

add bx,2

loop s

mov bx,0

mov cx,8

s1:

pop cs:[bx]

add bx,2

loop s1

mov ax, 4c00h

int 21h

code ends

end  start

  • 棧使用技巧:在內(nèi)存之間傳遞數(shù)據(jù),連個變量之間的傳遞,可以先用棧做中轉(zhuǎn),即先壓棧變量1

然后彈出來給變量2

  • 將數(shù)據(jù),代碼,棧放入不同的段

  • 實驗5

  • 非常重要:如果段中的數(shù)據(jù)占N個字節(jié)凑队,則程序加載后卖词,該段實際占有的空間為 ((N+15)/16)_16 哥艇。

解析:

N分為被16整除和不被16整除捻艳。

當(dāng)N被16整除時: 占有的空間為(N/16)_16

當(dāng)N不被16整除時: 占有的空間為(N/16+1)_16旗吁,N/16得出的是可以整除的部分翰灾,還有一個余數(shù)厂画,余數(shù)肯定小于16凸丸,加上一個16。

程序加載后分配空間是以16個字節(jié)為單位的袱院,也就是說如果不足16個字節(jié)的也分配16個字節(jié)屎慢。

兩種情況總結(jié)成一個通用的公式:((N+15)/16)_16

  • 每個段(例如 數(shù)據(jù)段,代碼段)必須是 16字節(jié)的整數(shù)倍(系統(tǒng)規(guī)定)所以小于16個字節(jié)的會自動的變成16個字節(jié)

  • 程序開始時ds指向psp比cs大10h,cx中存放著程序的長度

  • 編寫代碼,將a段和b段的數(shù)據(jù)相加,保存在c段中.


assume cs:code

a segment

db 1, 2, 3, 4, 5, 6, 7, 8

a ends

b segment

db 1, 2, 3, 4, 5, 6, 7, 8

b ends

c segment

db 0, 0, 0, 0, 0, 0, 0, 0

c ends

code segment

start:  mov ax, a

mov ds, ax

mov ax, b

mov es,ax

mov ax, c

mov ss,ax

mov ax,0

mov bx,0

mov cx,8

s: mov al,ds:[bx]

add al,es:[bx]

mov ss:[bx],al

inc bx

loop s

mov ax, 4c00h

int 21h

code ends

end start

第7章 更靈活的定位內(nèi)存的方法

  • and和or 指令

  • and指令,按位進(jìn)行與運(yùn)算,or按位進(jìn)行或運(yùn)算.

  • 第一個操作數(shù)必須寄存器或內(nèi)存單元(內(nèi)存單元必須指明尺寸)

  • 操作數(shù)不能是段寄存器,或ip寄存器

  • 兩個操作數(shù)的尺寸必須一致

  • 操作數(shù)不能同時是兩個內(nèi)存單元.

  • 關(guān)于ascii碼

  • 大寫字母在6590(41h5Ah)(0100000101011010)開始,小寫字母97122(61h-7Ah)(01100001~01111010)開始.

  • 大寫字母第6位為0,小寫字母第6位為1(索引從1開始算)

  • 重點是了解了字符的ascii碼的規(guī)律后,可以利用and和or指令進(jìn)行大小寫轉(zhuǎn)換

  • 數(shù)字的ascii碼4857(30h-49h)(00110000b00111001b).

  • 數(shù)字字符,跟二進(jìn)制數(shù)字的區(qū)別是數(shù)字字符第5位和第6位都為1而,數(shù)字值第7位和第8位都為0

  • 有助于理解ascii碼壓縮和非壓縮指令

  • 編碼方案:在顯示器上呈現(xiàn)的文字等都是文本字符串,在計算機(jī)內(nèi)部是以二進(jìn)制形式存儲,通過解碼,顯示器在屏幕上畫出文本,其中一種編碼方案是ascii碼.

  • 文本處理過程例子:我們按下鍵盤a鍵,這個按鍵的信息被送入計算機(jī),計算機(jī)用ascii嗎的規(guī)則對其進(jìn)行編碼,將其轉(zhuǎn)化為61h存儲在內(nèi)存的指定空間中,文本編輯軟件從內(nèi)存中取出61h,將其送到顯卡上的顯存中;工作在文本模式下的顯卡,用ascii碼的規(guī)則解釋顯存中的內(nèi)容.61h被當(dāng)作字符"a".顯卡驅(qū)動顯示器,將字符"a"的圖像畫在屏幕上.

  • db 'unIX' <=> db 75h,6eh, 49h,58h.

mov al, 'a' <=> mov al,97

  • 大小寫轉(zhuǎn)換問題例子代碼

  • 寫一段程序?qū)?'BaSic'字符串轉(zhuǎn)化為大寫,將'iNfOrMaTiOn'轉(zhuǎn)換為小寫


assume cs:code, ds:data

data segment

db 'BaSic'

db 'iNfOrMaTiOn'

data ends

code segment

start:

mov ax, data

mov ds, ax

mov bx,0

mov cx,5

s0:

mov al,[bx]

and al,11011111b

mov [bx],al

inc bx

loop s0

mov cx,11

mov bx,5

s1:

mov al,[bx]

or al,00100000b

mov [bx], al

inc bx

loop s1

mov ax, 4c00h

int 21h

code ends

end  start

  • 更靈活的尋址

  • [bx+idata] <=> idata[bx],[bx].idata

  • 可以用于數(shù)組尋址,例子如下,將數(shù)據(jù)段中第一個字符串轉(zhuǎn)換為大寫,第二個轉(zhuǎn)換為小寫


assume cs:code, ds:data

data segment

db 'BaSic'

db 'MinIX'

data ends

code segment

start:

mov ax, data

mov ds, ax

mov bx,0

mov cx,5

s0:

mov al,[bx]

and al,11011111b

mov [bx],al

mov al,[bx+5]

or al,00100000b

mov [bx+5],al

inc bx

loop s0

mov ax, 4c00h

int 21h

code ends

end  start

  • 技巧:因為第一個字符串和第二個字符串一樣長,我們就可以用bx+idata尋址,且可以用一個循環(huán)就可以達(dá)到轉(zhuǎn)換目的,因為長度一樣長.

  • C語言:a[i]<=>idata[i]

  • [bx+si],[bx+di]

  • [bx+si+idata],[bx+di+idata]默認(rèn)段地址在ds中.

  • [bp+si+idata],[bp+di+idata] 如果bp沒有給出段前綴,默認(rèn)段地址在ss中.

  • 注意事項 : bp和bx不能同時出現(xiàn),di和si也不能同時出現(xiàn).且di和si不能拆分成8位寄存器.

  • 尋址綜合應(yīng)用

  • 將data段中的每個單詞的首字母大寫.每個字符串占16個字節(jié).


assume cs:code, ds:data

data segment

db '1\. file        '

db '2\. edit        '

db '3\. search      '

db '4\. view        '

db '5\. options      '

db '6\. help        '

data ends

code segment

start:

mov ax, data

mov ds, ax

mov bx,0

mov cx, 6

s0:

mov al,[bx+3]

and al,11011111b

mov [bx+3],al

add bx,16

loop s0

mov ax, 4c00h

int 21h

code ends

end  start

  • 將data段中的每個單詞改為大寫字母,由于每個字符串一樣長,我們可以用嵌套循環(huán)

assume cs:codesg, ds:datasg

datasg segment

db 'ibm            '

db 'dec            '

db 'dos            '

db 'vax            '

datasg segment

codesg segment

start:mov ax,datasg

mov ds,ax

mov bx,0

mov cx,4

mov ax,0

s0: mov dx,cx

mov si,0

mov cx,3

s1:mov al,[bx+si]

and al,11011111b

mov [bx+si], al

inc si

loop s1

add bx,16

mov cx,dx

loop s0

codesg ends

end start

這里注意保存外層循環(huán)的cx值.可以用其它寄存器保存,也可以保存在內(nèi)存單元中,也可以保存在棧中

  • 將data段中的前四個字母改為大寫.

assume cs:codesg, ds:datasg

datasg segment

db '1\. display      '

db '2\. brows        '

db '3\. replace      '

db '4\. modify      '

datasg segment

codesg segment

start:

mov ax, datasg

mov ds,ax

mov bx,0

mov cx,4

s1:

push cx

mov cx,4

mov si,0

s2:

mov al,[bx+si+3]

and al,11011111b

mov [bx+si+3],al

inc si

loop s2

add bx, 16

pop cx

loop s1

mov ax, 4c00h

int 21h

codesg ends

end start

注意:si需要在循環(huán)中每次重置為0

  • 實驗6

  • 實踐本單元所有程序

第八章 數(shù)據(jù)處理的兩個基本問題

  • 兩個基本問題

  • 處理的數(shù)據(jù)在什么地方

  • cpu內(nèi)部(寄存器,緩存)

  • 端口

  • 內(nèi)存

  • 數(shù)據(jù)的尺寸有多長

  • 寄存器的大小指明尺寸

  • 用byte/word/dword ptr [尋址寄存器或段前綴]來指明.

  • 數(shù)據(jù)的位置表達(dá)

  • 立即數(shù):直接包含在指令中的立即數(shù)在執(zhí)行前是在cpu內(nèi)部的指令緩沖器中.

  • 寄存器

  • 內(nèi)存單元:bx系列尋址組合默認(rèn)段地址在ds中,bp系列組合默認(rèn)地址在ss中

  • 尋址的綜合應(yīng)用

  • 關(guān)于DEC公司的一條記錄(1982年)如下:

公司名稱:DEC

總裁姓名:Ken Olsen

排名:137

收入: 40(40億美元)

著名產(chǎn)品:PDP(小型機(jī))


mov ax,seg

mov ds,ax

mov bx,60h

mov word ptr [bx+0ch],38

mov word ptr [bx+0eh],70

mov byte ptr [bx+10h],'V'

inc bx

mov byte ptr [bx+10h],'A'

inc bx

mov byte ptr [bx+10h],'X'

  • 幾條指令

  • div指令

  • 格式:

div reg

div 內(nèi)存單元 //必須指明內(nèi)存單元尺寸

  • 指令說明

  • 除數(shù):有8位和16位兩種在reg或內(nèi)存單元中.

  • 被除數(shù):放ax或ax和dx中,如果除數(shù)為8位,則被除數(shù)為16位,默認(rèn)在ax中存放,如果除數(shù)為16位,則被除數(shù)則為32位.在dx和ax中存放,dx存放高16位,ax存放低16位

  • 結(jié)果:如果除數(shù)為8位,al存放商,AH存放余數(shù),如果除數(shù)為16位,則AX存放除法的商,dx存放除法操作的余數(shù)..

  • 例子:利用除法計算1000001/100

因為100001大于65536,化成16進(jìn)制為186A1


mov dx,1

mov ax,86A1h

mov bx,100

div bx

  • 例子:編程,利用除法指令計算1001/100

mov ax,1001

mov bl,100

div bl

  • 用div計算data段中的第一個數(shù)據(jù)除以第二個數(shù)據(jù)后的結(jié)果,商存在第三個數(shù)據(jù)的存儲單元中

assume cs:code, ds:data

data segment

dd 100001

dw 100

dw 0

data ends

code segment

start:

mov ax, data

mov ds,ax

mov bx,0

mov ax,[bx]

mov dx,[bx+2]

div word ptr [bx+4]

mov [bx+6],ax

mov ax, 4c00h

int 21h

code ends

end  start

  • dd偽指令:定義雙字型數(shù)據(jù). 還有db/dw/dq(八字節(jié))/dt(十字節(jié))

  • dup偽指令:db/dw/dd 重復(fù)次數(shù) dup (需要重復(fù)的數(shù)據(jù)列表)

eg:db 3 dup (0,1,2) 一共占用3*3=9個字節(jié)

  • 實驗7

  • 代碼如下:


assume cs:code,ds:data,es:table

data segment

db '1975','1976','1977','1978','1979','1980','1981','1982','1983'

db '1984','1985','1986','1987','1988','1989','1990','1991','1992'

db '1993','1994','1995'

dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514

dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000

dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226

dw 11452,14430,15257,17800

data ends

table segment

db 21 dup ('year summ ne ?? ')

table ends

code segment

start:

mov ax,data

mov ds,ax

mov ax,table

mov es,ax

mov bx,0

mov si,0

mov di,0

mov cx,21

s1:

mov ax,[bx]

mov es:[di],ax

mov ax,[bx+2]

mov es:[di+2],ax

mov byte ptr [di+4],' '

mov ax,84[bx]

mov es:[di+5],ax

mov ax,84[bx+2]

mov es:[di+7],ax

mov byte ptr [di+9],' '

mov ax,168[si]

mov es:[di+10],ax

mov byte ptr [di+12],' '

mov dx,86[bx]

mov ax,84[bx]

div word ptr 168[si]

mov es:[di+13],ax

mov es:[di+15],' '

add bx,4

add si,2

add di,16

loop s1

mov ax, 4c00h

int 21h

code ends

end start

第九章 轉(zhuǎn)移指令的原理

  • offset操作符

  • 操作符offset在匯編語言中是由編譯器處理的符號.功能是獲取標(biāo)號的偏移地址

  • 段標(biāo)號名稱就代表地址,所以不需要offset 操作符.

  • Nop指令占用一個字節(jié)

  • 轉(zhuǎn)移指令分類

  • 可以修改ip或同時修改CS或IP的指令統(tǒng)稱為轉(zhuǎn)移指令:

(1).只修改ip:段內(nèi)轉(zhuǎn)移

  • 8位數(shù)值范圍的修改IP,稱為短轉(zhuǎn)移

  • 修改范圍為16位的稱為近轉(zhuǎn)移

(2).同時修改Cs和IP時,稱為段間轉(zhuǎn)移.

  • 8086CPU的轉(zhuǎn)移指令分為以下幾類:

(1)無條件轉(zhuǎn)移指令(如:jmp)

(2)條件轉(zhuǎn)移指令

(3)循環(huán)指令

(4)過程

(5)中斷

  • 無條件跳轉(zhuǎn)jmp指令

  • 跳轉(zhuǎn)到標(biāo)號:

  • 短轉(zhuǎn)移:jmp sort 標(biāo)號 (機(jī)器碼中包含的是8位位移)

  • 近轉(zhuǎn)移:jmp near ptr 標(biāo)號(機(jī)器碼中包含16位位移)

位移計算:要跳轉(zhuǎn)的標(biāo)號的偏移地址 減掉 跳轉(zhuǎn)指令的下一條指令的偏移地址,位移在編譯時由匯編器算出.

  • 遠(yuǎn)轉(zhuǎn)移:jmp far ptr 標(biāo)號,cs=標(biāo)號段地址,ip=標(biāo)號偏移地址,該指令機(jī)器碼中不是用的位移表示.而是包含了轉(zhuǎn)移地址4個字節(jié).機(jī)器碼的高位字單元是段地址,低位時偏移地址

  • 轉(zhuǎn)移地址在寄存器:jmp 16位寄存器

  • 轉(zhuǎn)移地址在內(nèi)存中的jmp指令

  • 段內(nèi)轉(zhuǎn)移:jmp word ptr 內(nèi)存單元地址

  • 段間轉(zhuǎn)移:jmp dword ptr 內(nèi)存單元地址(高字單元是段地址,低地址字單元是偏移地址)

  • 條件轉(zhuǎn)移指令jcxz

  • 所有條件轉(zhuǎn)移都是短轉(zhuǎn)移.,在對應(yīng)的機(jī)器碼中包含轉(zhuǎn)移的位移.

  • 格式:jcxz 標(biāo)號,當(dāng)cx=0時就跳轉(zhuǎn)到標(biāo)號處.

  • 例子程序:補(bǔ)全程序,利用jcxz指令,實現(xiàn)在內(nèi)存2000h段中,查找第一個值為0的字節(jié),找到后,將它的偏移地址存儲在dx中


assume cs:code

code segment

start:

mov ax,2000h

mov ds,ax

mov bx,0

s:

mov cx, 0

mov cl,[bx]

jcxz ok

inc bx

jmp short s

ok:

mov dx, bx

mov ax, 4c00h

int 21h

code ends

end  start

  • loop指令

  • 所有的循環(huán)指令都是短轉(zhuǎn)移.對應(yīng)的機(jī)器碼包含的是位移.

  • 例子程序:例子程序:補(bǔ)全程序,利用loop指令,實現(xiàn)在內(nèi)存2000h段中,查找第一個值為0的字節(jié),找到后,將它的偏移地址存儲在dx中


assume cs:code

code segment

start:  mov ax,2000h

mov ds,ax

mov bx,0

s:mov cl,[bx]

mov ch,0

inc cx

inc bx

loop s

ok:dec bx

mov dx,bx

mov ax,4c00h

int 21h

code ends

end start

inc cx是防止當(dāng)cx為0時,loop指令會首先cx=cx-1會變成0ffffh,就會循環(huán)ffff次.

  • 實驗

  • 實驗8:


assume cs:codesg

codesg segment

mov ax,4c00h

int 21h

start: mov ax,0            ax=0

s: nop                占一字節(jié),機(jī)器碼90

nop                占一字節(jié),機(jī)器碼90

mov di,offset s    (di)=s偏移地址

mov si,offset s2    (si)=s2偏移地址

mov ax,cs:[si]      (ax)=jmp short s1指令對應(yīng)的機(jī)器碼EBF6

mov cs:[di],ax      jmp short s1覆蓋s處指令2條nop指令

s0: jmp short s        執(zhí)行到這里,不會再繼續(xù)向下執(zhí)行忽洛,直接跳回mov ax,4c00h了

s1: mov ax,0

int 21h

mov ax,0

s2: jmp short s1

nop

codesg ends

end start

因為jmp short s1<=>EB 位移.位移等于S1標(biāo)號偏移地址減去nop指令的偏移地址大約為-10.當(dāng)跳轉(zhuǎn)到s處執(zhí)行jmp short s1,實際上是執(zhí)行EB -10.會向前跳轉(zhuǎn)10個字節(jié),也就是說會執(zhí)行程序返回的代碼.

  • 實驗9:根據(jù)材料編程:在屏幕中間分別顯示綠色腻惠,綠底紅色,白色藍(lán)底的字符串’welcome to masm!’

  • 顯示字符相關(guān)知識: B8000h-bffffh共32kb的空間,為80*25彩色字符模式的顯示緩存區(qū).一個字符占兩個字節(jié),后面的字節(jié)是該字符的一些顏色屬性信息.所以一屏幕內(nèi)容占緩沖區(qū)4000b約等于4kb


assume cs:code, ds:data

data segment

db 'welcome to masm!'

data ends

code segment

start:

mov ax, data

mov ds, ax

mov bx,0

mov ax,0b800h

mov es, ax

mov di,11*160+72

mov cx,16

s:

mov al,[bx]

mov es:[di], al

mov byte ptr es:[di+1],00000010b

mov es:160[di],al

mov byte ptr es:161[di],00100100b

mov es:320[di],al

mov byte ptr es:321[di],01110001b

add di,2

inc bx

loop s

mov ax, 4c00h

int 21h

code ends

end  start

第十章 call和ret指令

  • ret和retf指令

  • ret<=>pop ip<=>(ip)=((ss)*16+(sp)),(sp)=(sp)+2

  • retf<=>pop ip,pop cs <=>(ip)=((ss)_16+(sp)),(sp)=(sp)+2

(cs)=((ss)_16+(sp)),(sp)=(sp)+2

  • call指令

  • call指令執(zhí)行的步驟

  • 將當(dāng)前call指令后的下一條指令的ip,或cs和ip壓入棧中

  • 跳轉(zhuǎn)到目標(biāo)地址執(zhí)行

(sp)=(sp) - 2

((ss)*16+(sp)) = (ip)

(ip)=(ip)+16位位移

  • call指令不能實現(xiàn)短轉(zhuǎn)移,此外轉(zhuǎn)移的方法同jmp指令一樣.

  • call 標(biāo)號:16位位移=標(biāo)號處的地址-call指令后的第一個字節(jié)的地址, 位移范圍為-32768~32767

有等同于 push ip,jmp near ptr 標(biāo)號

  • call far ptr 標(biāo)號:實現(xiàn)的是段間轉(zhuǎn)移.

push cs,push ip, jmp far ptr 標(biāo)號

  • 轉(zhuǎn)移地址在寄存器中的call指令:call 16位reg

push ip, jmp reg

  • 轉(zhuǎn)移地址在內(nèi)存中的call指令:

  • call word ptr 內(nèi)存單元地址

push ip, jmp word ptr 內(nèi)存單元地址

  • call dword ptr 內(nèi)存單元地址

push cs, push ip,jmp dword ptr 內(nèi)存單元地址

  • call和ret的配合使用

  • 子程序框架:


assume cs:code

code segment

main:

call sub1

:

:

call sub2

:

:

mov ax, 4c00h

int 21h

sub1:

:

:

sub2:

:

code ends

所以c語言中的函數(shù)名其實就是一個標(biāo)識子程序的地址

  • mul指令

  • 要求:

  • 兩個相乘的數(shù),要么都是8位,要么都是16位,如果是8位,那么一個乘數(shù)默認(rèn)放在AL中,另一個放在8位reg或內(nèi)存單元中,如果是16位,一個默認(rèn)在ax中,另一個放在16位reg或內(nèi)存單元中

  • 結(jié)果:如果是8位乘法,結(jié)果默認(rèn)放在AX中,如果是16位乘法,結(jié)果高位默認(rèn)放在dx中,低位放在ax中.

  • 格式:mul reg/內(nèi)存單元(必須指明內(nèi)存單元尺寸)

  • 例子:計算100*10,因為兩個乘數(shù)都是8位,所以用8位乘法


mov al,100

mov bl,10

mul bl

計算 100 * 10000,必須用16位乘法


mov ax,100

mov bx,10000

mul bx

  • 模塊化程序設(shè)計

  • 參數(shù)和結(jié)果傳遞問題:

  • 用寄存器傳遞參數(shù)和用寄存器存儲函數(shù)結(jié)果值

  • 例子:計算n的立方,用bx傳遞參數(shù)dx和ax返回結(jié)果值


cube:

mov ax,bx

mul bx

mul bx

ret

  • 參數(shù)的批量傳遞:可以將參數(shù)放在一組內(nèi)存單元中,然后用si等間接寄存器指向它.返回值也可以這樣做.

  • 例子:將一個si指向的全是字母的字符串轉(zhuǎn)換為大寫


capital:

and byte ptr [si], 11011111b

inc si

loop capital

ret

  • 用棧來傳遞參數(shù)

  • 寄存器沖突問題:

  • 例子程序:將一個全是字母,以0結(jié)尾的字符串,轉(zhuǎn)化為大寫si指向該字符串


capital:mov cl, [si]

mov ch,0

jcxz ok

and byte ptr [si],11011111b

inc si

jmp short capital

ok : ret

如果調(diào)用該子程序中的代碼中使用了cx寄存器,將產(chǎn)生錯誤.解決辦法是在該子程序開頭壓棧保存需要使用的寄存器,在返回前彈出該寄存器的值.改正如下


capital:push cx

push si

change:

mov cl, [si]

mov ch,0

jcxz ok

and byte ptr [si],11011111b

inc si

jmp short change

ok :pop si

pop cx

ret

  • 所以子程序框架如下:

子程序標(biāo)號:

子程序中使用的寄存器入棧保存

子程序指令標(biāo)號:

....

子程序返回標(biāo)號:

子程序中保存的寄存器出椨椋恢復(fù)

子程序返回(ret,retf)

  • 實驗10 編寫子程序

  • 顯示字符串子程序:show_str

  • 功能:在指定的位置,用指定的顏色,顯示一個用0結(jié)束的字符串

  • 參數(shù):(dh)=行號(取值范圍024),(dl)=列號(取值范圍是079).(cl)=顏色,ds:si指向字符串的首地址

  • 返回值:無


show_str:

push ax

push bx

push cx

push dx

push es

push si

push di

begn:

mov ax,0b800h

mov es,ax

mov al,160

mul dh

mov bx,ax

mov al,2

mul dl

add bx,ax

mov di,bx

mov al,cl

mov ch,0

s:

mov cl,[si]

jcxz retn

mov es:[di],cl

mov es:[di+1],al

inc si

add di,2

jmp short s

retn:

pop di

pop si

pop es

pop dx

pop cx

pop bx

pop ax

ret

  • 解決觸發(fā)溢出問題子程序:

  • 名稱:divdw

  • 功能:進(jìn)行不會產(chǎn)生溢出的除法運(yùn)算,被除數(shù)位dword型,除數(shù)位word型.結(jié)果為dword型

  • 參數(shù):(ax)=dword型數(shù)據(jù)的低16位,(dx)=dword型數(shù)據(jù)的高16位,(cx)=除數(shù)

  • 返回:(dx)=結(jié)果的高16位,(ax)=結(jié)果的低16位,(cx)=余數(shù)


divdw:

push ax

push bx

push cx

push dx

begn:

mov bx,ax

mov ax,dx

mov dx,0

div cx

push ax

mov ax,bx

div cx

mov cx,dx

pop dx

retn:

pop dx

pop cx

pop bx

pop ax

ret

  • 將數(shù)值以十進(jìn)制形式顯示:

  • 名稱:dtoc

  • 功能:將word型數(shù)據(jù)轉(zhuǎn)變?yōu)楸硎臼M(jìn)制數(shù)的字符串,字符串以0結(jié)尾

  • 參數(shù):(ax)=word型數(shù)據(jù),ds:si指向字符串首地址

  • 返回值:無


dtoc:

push ax

push bx

push cx

push dx

push ds

push si

push 0

begn:

mov dx,0

mov bx,10

div bx

mov cx,ax

jcxz sw1

add dx,30h

push dx

jmp short begn

sw1:add dx,30h

push dx

sw2:

pop cx

jcxz retn

mov [si],cl

inc si

jmp short sw2

retn:

mov [si+1],0

pop si

pop ds

pop dx

pop cx

pop bx

pop ax

ret

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末集灌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子复哆,更是在濱河造成了極大的恐慌欣喧,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寂恬,死亡現(xiàn)場離奇詭異续誉,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)初肉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門酷鸦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人牙咏,你說我怎么就攤上這事臼隔。” “怎么了妄壶?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵摔握,是天一觀的道長。 經(jīng)常有香客問我丁寄,道長氨淌,這世上最難降的妖魔是什么泊愧? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮盛正,結(jié)果婚禮上删咱,老公的妹妹穿的比我還像新娘。我一直安慰自己豪筝,他們只是感情好痰滋,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著续崖,像睡著了一般敲街。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上严望,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天多艇,我揣著相機(jī)與錄音,去河邊找鬼著蟹。 笑死墩蔓,一個胖子當(dāng)著我的面吹牛梢莽,可吹牛的內(nèi)容都是我干的萧豆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼昏名,長吁一口氣:“原來是場噩夢啊……” “哼涮雷!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起轻局,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤洪鸭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后仑扑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體览爵,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年镇饮,在試婚紗的時候發(fā)現(xiàn)自己被綠了蜓竹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡储藐,死狀恐怖俱济,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情钙勃,我是刑警寧澤蛛碌,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站辖源,受9級特大地震影響蔚携,放射性物質(zhì)發(fā)生泄漏希太。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一酝蜒、第九天 我趴在偏房一處隱蔽的房頂上張望跛十。 院中可真熱鬧,春花似錦秕硝、人聲如沸芥映。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽奈偏。三九已至,卻和暖如春躯护,著一層夾襖步出監(jiān)牢的瞬間惊来,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工棺滞, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留裁蚁,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓继准,卻偏偏與公主長得像枉证,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子移必,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容