8086CPU有四个段寄存器:CS,DS,SS,ES段寄存器用来提供段地址
CS:代码段寄存器IP:指令指针寄存器修改CS,IP:jmp段地址:偏移地址仅修改IP的内容:jmp某一合法寄存器jmpax用ax中的值修改IP下面的3条指令执行后,cpu几次修改IP?都是在什么时候?最后IP中的值是多少?
movax,bx
subax,ax
jmpax
答:一共修改四次
第一次:读取movax,bx之后
第二次:读取subax,ax之后
第三次:读取jmpax之后
第四次:执行jmpax修改IP
最后IP的值为0000H,因为最后ax中的值为0000H,所以IP中的值也为0000H
-r:查看寄存器内容-rax:修改ax的内容-t:执行指令-d:查看内存中内容-u:查看内存中内容,将机器指令翻译成汇编指令-e:改写内存中内容(机器指令)-a:以汇编指令的格式在内存中写入一条机器指令
DS寄存器通常用来存放要访问的数据的段地址若要读区10000H单元内容到寄存器:
movbx,1000Hmovds,bxmoval,[0]不可以直接movds,1000H8086cpu不支持直接将数据送入段寄存器
将al中数据送入内存单元10000H:
movbx,1000Hmovds,bxmov[0],al8086cpu有16根数据线,一次性可以传一个字movmov段寄存器,寄存器是可以的但是mov寄存器,段寄存器可以吗?答案是可以。
段寄存器SS:存放栈顶的段地址寄存器SP:存放栈顶的偏移地址任意时刻,SS:SP指向栈顶元素
movax,1000Hmovss,ax//不能直接mov数据到段寄存器movsp,0010Hpushaxpushbxpushds第一个程序!assumecs:abcabcsegment movax,2 addax,ax addax,ax movax,4c00H int21Habcendsend.asm源代码文件,masm后.obj,link后.exe可以加一个入口,然后debug,debug.exe要放在文件夹中。
若源程序中这样写movax,[0]编译器会认为是movax,0所以要这样:movax,[bx]bx中放偏移地址。在debug中可以movax,[0]
执行loop时
movcx,11s:addax,axloops以上代码共执行11次add。注意:在汇编源程序中数据不能以字母开头!所以movax,0ffffhdebug时用g命令可以直接跳到想要跳到的ip处。-g000B也可以在ip在loop那行时执行p命令。
在一般的PC机中,DOS方式下,DOS和其他合法程序一般都不会用0:200h-0:2ffh的256个字节的空间,所以我们使用这段空间是安全的。把ffff:0-ffff:b中的数据放入0020:0-0020:b中:
assumecs:codecodesegment movax,0ffffH movds,ax movax,0020H moves,ax movbx,0 movcx,12s: movdl,[bx] moves:[bx],dl incbx loops movax,4c00H int21Hcodeendsend使用es存目标段地址,避免在循环中重复改变ds
dw:defineword
assumecs:codecodesegment dw1h,2h,3h,4h movbx,0 movax,0 movcx,4s:addax,cs:[bx] addbx,2 loops movax,4c00h int21hcodeendsend1h在cs:0处,依次放4个字这样的话cpu会把这些字转换成指令,而这些并不是指令,cpu会误读指令,我们可以在第一条需要执行的代码前加start(或其他任意,只要和end后对应):
assumecs:codecodesegment dw1h,2h,3h,4hstart: movbx,0 movax,0 movcx,4s:addax,cs:[bx] addbx,2 loops movax,4c00h int21hcodeendsendstartend除了通知编译器程序结束外,还可以通知编译器程序的入口在什么地方。
利用栈,将程序中定义的数据逆序存放
assumecs:codesgcodesgsegment dw0123h,0456h,8976h,0987h,4576h,0345h,0984h,7678h dw0,0,0,0,0,0,0,0;用dw定义8个字型数据,程序加载后将取得8个字的内存空间,后面把这些空间当作栈来使用。start:movax,cs movss,ax movsp,32 movbx,0 movcx,8s: pushcs:[bx] addbx,2 loops movbx,0 movcx,8s1:popcs:[bx] addbx,2 loops1 movax,4c00h int21hcodesgendsendstart将数据,代码,栈放入不同的段assumecs:codesg,ds:data,ss:stackdatasegment dw0123h,0456h,8976h,0987h,4576h,0345h,0984h,7678hdataendsstacksegment dw0,0,0,0,0,0,0,0stackendscodesgsegmentstart:movax,stack movss,ax movsp,16 movax,data movds,ax movcx,8 movbx,0s: push[bx] addbx,2 loops movcx,8 movbx,0s1:pop[bx] addbx,2 loops1 movax,4c00h int21hcodesgendsendstart不可以movds,data对于如下定义的段namesegment...nameends如果段中的数据占N个字节,程序加载后,该段实际占有的空间为16*(N/6+1)用push指令将a段中的前8个字型数据逆序存放到b段中:
assumecs:codeasegment dw1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh,0fh,0ffhaendsbsegment dw0,0,0,0,0,0,0,0bendscodesegmentstart: movax,a movds,ax movax,b movss,ax movsp,16 movbx,0 movcx,8s: push[bx] addbx,2 loops movax,4c00h int21hcodeendsendstart更灵活的定位内存地址大小写转换:小写字母的ASCII码比对应的大写字母大32,即100000B.大写->小写,oral,00100000B;小写->大写,andal,11011111B
assumecs:code,ds:datadatasegment db'BaSiC' db'iNfOrMaTiOn'dataendscodesegmentstart: movax,data movds,ax movbx,0 movcx,5 s:moval,[bx]andal,11011111B mov[bx],al;小写to大写 incbx loops movbx,5 movcx,11s1:moval,[bx]oral,00100000B mov[bx],al;大写to小写 incbx loops1 movax,4c00H int21Hcodeendsendstart[bx+idata]作为偏移地址movax,[bx+5]movax,[5+bx]movax,5[bx]movax,[bx].5
assumecs:code,ds:datadatasegment db'BaSiC';转换为大写 db'iNfOr';转换为小写dataendscodesegmentstart: movax,data movds,ax movbx,0 movcx,5 s:moval,[0+bx] andal,11011111b mov[0+bx],al moval,[5+bx] oral,00100000b mov[5+bx],al incbx loops movax,4c00H int21HcodeendsendstartSI和DISI和DI不能分成两个8位寄存器使用。
movsi,0movax,[si]movdi,0movax,[di]movdi,0movax,[di+123]assumecs:code,ds:datadatasegment db'welcometomasm!' db'................'dataendscodesegmentstart: movax,data movds,ax movsi,0 movcx,16 s:moval,[si] mov[16+si],al incsi loops movax,4c00h int21hcodeendsendstart[bx+si],[bx+di][bx+si+idata],[bx+di+idata]练习:
assumecs:codesg,ds:datasgdatasgsegment db'abc' db'def' db'ghi' db'gkl'datasgendscodesgsegmentstart: movax,datasg movds,ax movbx,0 movcx,4 s:movdx,cx movcx,3 movdi,0 s1: moval,[bx+di] andal,11011111b mov[bx+di],al incdi loops1 addbx,16 movcx,dx loops movax,4c00h int21hcodesgendsendstart但是用dx暂存cx不合适,dx有可能会用到。使用栈:
movwordptrds:[0],1incwordptr[bx]incwordptrds:[0]addwordptr[bx],2若是字节型,byteptrpush只push字型数据pushds:[1]
计算100001/100100001=186a1h
movdx,1hmovax,86a1hmovbx,100divbx执行完成后,(ax)=03e8h(100),(dx)=1计算1001/100
movax,1001movbl,100divbl执行后,(al)=0ah,(ah)=1
用来定义doubleword,32位
assumecs:code,ds:datadatasegment dd100001 dw100 dw0dataendscodesegmentstart:movax,data movds,ax movax,ds:[0] movdx,ds:[2] movbx,ds:[4] divbx movds:[6],ax movax,4c00h int21hcodeendsendstart伪指令dup和db,dw,dd配合使用,进行数据的重复。
assumecs:codecodesegmentstart:movax,offsetstart;相当于movax,0s:movax,offsets;相当于movax,3codeendsendstart把s处的第一条指令复制到s0处:
assumecs:codecodesegments: movax,bx;2bytes movsi,offsets movdi,offsets0 movax,cs:[si] movcs:[di],axs0:nop;1byte nopcodeendsendjmp指令无条件跳转
movax,0123hmovds:[0],axjmpwordptrds:[0]跳转到ip0123h处jmpdwordptr内存单元地址(cs)=(内存单元地址+2)(ip)=(内存单元地址)movax,0123hmovds:[0],axmovwordptrds:[2],0jmpdwordptrds:[0](cs)=0,(ip)=0123hjcxz指令有条件转移指令,所有的有条件转移指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址。对ip的修改范围都为-128~127格式:jcxz标号当(cx)=0时,(IP)=(IP)+8位位移当(cx)!=0时,程序向下执行
短转移,在对应的机器码中包含转移的位移,而不是目的地址。对ip的修改范围-128~127
jmpshort标号jmpnearptr标号jcxz标号loop标号在他们的机器码中不包含转移的目的地址,包含的是到目的地址的位移距离。转移范围有限,超出编译时编译器将报错。
注意:jmp2000:1000这样的转移指令实在debug中使用的,汇编编译器并不认识。
实验8:
ret指令用栈中的数据,修改ip的内容,从而实现近转移。cpu执行ret指令时,进行下面两步操作:
cpu执行call指令,进行两步操作:
call不能实现短转移,除此之外,call实现转移的方法和jmp指令的原理相同。
call16位寄存器功能:ip入栈,跳到ip为寄存器内容处
转移地址在内存中
callwordptr内存单元地址段内先puship再跳到内存中存着的ip
calldwordptr内存单元地址先pushcs,puship,再跳内存中第一个字存着要跳的ip,下一个字存着要跳的cs
movsp,10hmovax,0123hmovds:[0],axmovwordptrds:[2],0calldwordptrds:[0]执行后,(cs)=0,(ip)=0123h,(sp)=0ch
mulregmul内存单元用al或者ax中的数据×,都是8位或者都是16位。8位的两个数结果存在ax,16位的两个数结果高位存在DX,低位存在AX计算100*10:
moval,100movbl,10mulbl结果(ax)=1000计算100*10000:
movax,100movbx,10000mulbx结果(dx)=000fh,(ax)=4240h
编程:计算data段中第一组数据的3次方,结果存在后面一组dword中
assumecs:code,ds:datadatasegment dw1,2,3,4,5,6,7,8 dd0,0,0,0,0,0,0,0dataendscodesegmentstart: movax,data movds,ax movsi,0 movdi,0 movcx,8 s: movax,ds:[si] callcube movds:[16+di],ax movds:[16+di+2],dx addsi,2 adddi,4 loops movax,4c00h int21h cube: movbx,ax mulbx mulbx ret codeendsendstart批量数据的传递把批量数据放到内存中,然后把他们所在内存空间的首地址放到寄存器。
assumecs:codedatasegment db'Welcometomasm!',0dataendscodesegmentstart: movdh,8 movdl,3 movcl,2 movax,data movds,ax movsi,0 callshow_str movax,4c00h int21hshow_str: moval,160 muldh movdi,ax adddl,dl movdh,0 adddi,dx movax,0B800h moves,ax movdl,cl;dl存颜色信息 movch,0 s: movcl,[si] jcxzok moves:[di],cl moves:[di+1],dl incsi adddi,2 jmpshorts ok:ret codeendsendstart实验10-2
assumecs:code,ds:datadatasegment dw0,0,0,0,0;分别存被除数的低16位,高16位,除数;公式右半部分商,余数dataendscodesegmentstart: movax,data movds,ax movax,4240h movdx,000fh movcx,0ah movds:[0],ax movds:[2],dx movds:[4],cx calldivdw movcx,4c00h int21h divdw: movax,ds:[2] movdx,0 divcx;rem(H/N)结果在dx movax,ds:[0] divcx;公式右半部分结果,商在ax,余数在dx movds:[6],ax movds:[8],dx movax,ds:[2] movdx,0 divcx;int(H/N)结果在ax movdx,ax movax,ds:[6] movcx,ds:[8] retcodeendsendstart 改进:
assumecs:codestacksegment dw0,0,0,0,0stackendscodesegmentstart: movax,stack movss,ax movsp,10 movax,4240h movdx,000fh movcx,0ah calldivdw movcx,4c00h int21h divdw: pushax movax,dx movdx,0 divcx;int(H/N)--ax,rem(H/N)--dx movbx,ax;bx:int(H/N) popax divcx;[res(H/N)*65536+L]/N movcx,dx movdx,bx retcodeendsendstart 实验10-3
assumecs:codedisplaycontentsegment db10dup(0)displaycontentendstmpsegment;用于逆序 db10dup(0)tmpendscodesegmentstart: movax,12666 movbx,tmp moves,bx movbp,0 movbx,displaycontent movds,bx movsi,0 calldtoc;转换到10进制的字符并存到displaycontent中 movdh,8;开始准备显示displaycontent中的内容 movdl,3 movcl,2 movsi,0 callshow_str movax,4c00h int21h dtoc: movdx,0 movcx,10 divcx;ax:商,dx:余数 adddx,30h moves:[bp],dl movcx,ax jcxzdtocok incbp jmpshortdtocdtocok: moval,es:[bp] movds:[si],al movcx,bp jcxzok_1 incsi decbp jmpshortdtocok ok_1:ret show_str: moval,160 muldh movdi,ax adddl,dl movdh,0 adddi,dx movax,0B800h moves,ax movdl,cl;dl存颜色信息 movch,0 s: movcl,[si] jcxzok moves:[di],cl moves:[di+1],dl incsi adddi,2 jmpshorts ok:retcodeendsendstart课程设计1
0--CF进位标志位无符号数运算产生进位CF=1
OF有符号数运算超过机器所能表示的范围产生溢出。例如8位al寄存器范围,如果是有符号数,-128~127溢出针对有符号数,进位针对无符号数!
adc指令adc操作对象1操作对象2功能:操作对象1+操作对象2+CF
moval,98haddal,98hadcah,0执行后(ah)=1
movax,2movbx,1subbx,ax;借位,CF=1adcax,1执行后(ax)=4编程计算1EF000H+201000H,结果放在ax(高16位)和bx(低16位)中:
assumecs:codecodesegmentstart: movbx,0f000h movax,1eh addbx,1000h adcax,20h movax,4c00h int21hcodeendsendstartadc指令也可能改变CF!编程计算1EF0001000h+2010001EF0H结果放在ax+bx+cx中
assumecs:codecodesegmentstart: movcx,1000h movbx,0f000h movax,1eh addcx,1ef0h adcbx,1000h adcax,20h movax,4c00h int21hcodeendsendstart计算两个128位数据的和:
assumecs:code,ds:datadatasegment db88h,88h,88h,88h,88h,88h,88h,88h,88h,88h,88h,88h,88h,88h,88h,88h db88h,88h,11h,11h,11h,11h,11h,11h,11h,11h,11h,11h,11h,11h,11h,11hdataendscodesegmentstart: movax,data movds,ax movsi,0 movdi,16 movcx,8 subax,ax calladd128 movax,4c00h int21h add128: movax,[si] adcax,[di] mov[si],ax incsi;必须inc,不可以add,inc不影响CF incsi incdi incdi loopadd128 retcodeendsendstartsbb借位减法指令sbbax,bx(ax)=(ax)-(bx)-CF计算003E1000H-00202000H
assumecs:code,ds:datadatasegment db8,11,8,1,8,5,8,38dataendscodesegmentstart: movax,data movds,ax movsi,0 movax,0 movcx,8 s: movbl,[si] cmpbl,8 jneskip incax skip: incsi loops movax,4c00h int21hcodeendsendstart小于8:
assumecs:code,ds:datadatasegment db8,11,8,1,8,5,8,38dataendscodesegmentstart: movax,data movds,ax movsi,0 movax,0 movcx,8 s: movbl,[si] cmpbl,8 jnbskip incax skip: incsi loops movax,4c00h int21hcodeendsendstartDF标志和串传送指令DF:方向标志位在串处理指令中,控制每次操作后si,di的增减
把前面的字符串复制到后面:
assumecs:code,ds:datadatasegment db'Welcometomasm!' db16dup(0)dataendscodesegmentstart: movax,data movds,ax moves,ax movsi,0 movdi,16 movcx,16 cld repmovsb movax,4c00h int21hcodeendsendstart把F000H段中最后16个字节数据存到data段中:
assumecs:code,ds:datadatasegment db16dup(0)dataendscodesegmentstart: movax,0F000h movds,ax movax,data moves,ax movsi,0ffffh movdi,15 movcx,16 std repmovsb movax,4c00h int21hcodeendsendstartpushf和popfpushf:将标志寄存器的值入栈popf:从栈中弹出数据,送入标志寄存器
实验11:将data中数据的小写字母转为大写
assumecs:codesgdatasgsegmentdb"Beginner'sAll-purposeSymbolicInstructionCode.",0datasgendscodesgsegmentstart:movax,datasgmovds,axmovsi,0calllettercmovax,4c00Hint21Hletterc:movcl,[si] movch,0d076a:0d jcxzdone cmpcl,97 jbskip cmpcl,122 jaskip andcl,11011111B mov[si],cl skip: incsi jmpshortletterc done: retcodesgendsendstart内中断在中断过程中,寄存器的入栈顺序是标志寄存器,CS,IP,而iret的出栈顺序为IP,CS,标志寄存器,刚好对应。中断处理程序的cs和ip存放在0000:0000--0000:03FF中,即中断向量表。一般,0000:0200--0000:02FF的256字节是空的,是一段安全的内存空间。ip在低地址,cs在高地址N号中断的处理程序的ip在4N,cs在4N+2一个中断处理程序占4个字节,前两个字节是ip,后两个是cs
编程处理0号中断:
assumecs:codecodesegmentstart: movax,cs movds,ax movsi,offsetdo0 movax,0 moves,ax movdi,0200h movcx,offsetdo0end-offsetdo0;计算do0程序段的长度 cld repmovsb movax,0 movds,ax movdx,0200h movds:[0],dx;0号中断处理程序的ip movdx,0 movds:[2],dx ;cs movax,4c00h int21h do0:jmpshortdo0start;此程序将要放到内存0:0200处 db"Notgood,0#INT!",0do0start:movax,0 movds,ax movax,0B800h moves,ax movsi,0202h movdi,7*160+20 movch,0s: movcl,[si] jcxzdone moves:[di],cl movcl,02h moves:[di+1],clincsi adddi,2jmpshorts done:movax,4c00h int21hdo0end:nop codeendsendstart单步中断CPU在执行完一条指令后,如果监测到标志寄存器的TF位为1,则产生单步中断,引发中断过程。单步中断的中断类型码是1引发的中断过程如下:
cpu执行intn指令,相当于引发一个n号中断的中断过程,过程如下:
例1编写int7ch的中断处理函数并安装在中断例程的最后,使用iret指令iret指令的功能为:popippopcspopf中断程序及安装:
assumecs:codecodesegmentstart:movax,cs movds,ax movsi,offsetsqr movax,0 moves,ax movdi,200h movcx,offsetsqrend-offsetsqr cld repmovsb movax,0 movds,ax movax,200h movds:[7ch*4],ax;修改7ch中断的中断处理函数的ip movax,0 movds:[7ch*4+2],ax movax,4c00h int21hsqr:mulax iret sqrend:nopcodeendsendstart测试程序:
assumecs:codecodesegmentstart:movax,3456 int7ch addax,ax adcdx,dx movax,4c00h int21hcodeendsendstart例2转换字符串为大写中断例程及安装:
assumecs:codecodesegmentstart:movax,cs movds,ax movsi,offsetsqr movax,0 moves,ax movdi,200h movcx,offsetsqrend-offsetsqr cld repmovsb movax,0 movds,ax movax,200h movds:[7ch*4],ax;修改7ch中断的中断处理函数的ip movax,0 movds:[7ch*4+2],ax movax,4c00h int21hsqr:movcl,ds:[si] movch,0jcxzdoneandcl,11011111b movds:[si],cl incsi jmpshortsqr done:iret sqrend:nopcodeendsendstart用到中断的程序:
assumecs:codedatasegment db'conversation',0dataendscodesegmentstart:movax,data movds,ax movsi,0 int7ch movax,4c00h int21hcodeendsendstart例3用int7ch实现loop的功能中断程序:
assumecs:codecodesegmentstart:movax,cs movds,ax movsi,offsetlp movax,0 moves,ax movdi,200h movcx,offsetlpend-offsetlp cld repmovsb movax,0 movds,ax movax,200h movds:[7ch*4],ax;修改7ch中断的中断处理函数的ip movax,0 movds:[7ch*4+2],ax movax,4c00h int21hlp:pushbp movbp,sp deccx jcxzdone addss:[bp+2],bxdone:popbpiretlpend:nopcodeendsendstart测试程序:
assumecs:codecodesegmentstart:movax,0b800h moves,ax movdi,160*10 movbx,offsets-offsetse movcx,80s:movbyteptres:[di],'!' adddi,2 int7ch;int时,压栈的ip是se的位置,此ip+bx可以得到s的位置se:nop movax,4c00h int21hcodeendsendstartint10h
movah,2;2号子程序:放置光标movbh,0;第0页movdh,5;dh中放行号movdl,12;dl中放列号int10h(ah)=2表示调用第10h号中断例程的2号子程序,功能为设置光标位置
movah,9moval,'a';字符movbl,7;颜色属性movbh,0;第0页movcx,3;重复个数int10h9号子程序,功能为在光标位置显示字符。int21h
ds:dx指向字符串;要显示的字符串需要用$作为结束符movah,9int21h在光标位置显示字符串,可以提供要显示的字符串的地址作为参数。实验13_1中断程序及安装:
assumecs:codecodesegmentstart: movax,cs movds,ax movsi,offsetintcode movax,0 moves,ax movdi,0200h movcx,offsetintcodeend-offsetintcode cld repmovsb movax,0 movds,ax movwordptrds:[7ch*4],0200h movwordptrds:[7ch*4+2],0 movax,4c00h int21hintcode:moval,160 muldh movdi,ax adddl,dl movdh,0 adddi,dx movax,0B800h moves,ax movdl,cl movch,0 s: movcl,ds:[si] jcxzdone moves:[di],cl moves:[di+1],dl incsi adddi,2 jmpshortsdone:iretintcodeend:nopcodeendsendstart测试中断的程序:
assumecs:codedatasegment db"welcometomasm!",0dataendscodesegmentstart: movdh,10 movdl,10 movcl,2 movax,data movds,ax movsi,0 int7ch movax,4c00h int21hcodeendsendstart实验13_2中断程序及安装:
assumecs:codecodesegmentstart: movax,cs movds,ax movsi,offsetintcode movax,0 moves,ax movdi,0200h movcx,offsetintcodeend-offsetintcode cld repmovsb movax,0 movds,ax movwordptrds:[7ch*4],0200h movwordptrds:[7ch*4+2],0 movax,4c00h int21hintcode:deccx jcxzdone movbp,sp addss:[bp],bxdone: iretintcodeend:nopcodeendsendstart测试程序:
assumecs:codecodesegmentstart:movax,0b800h moves,ax movdi,160*12 movbx,offsets-offsetse movcx,80 s: movbyteptres:[di],'!' adddi,2 int7chse:nop movax,4c00h int21hcodeendsendstart实验13_3
assumecs:codecodesegments1: db'Good,better,best,','$'s2: db'Neverletitrest,','$'s3: db'Tillgoodisbetter,','$'s4: db'Andbetter,best.','$'s: dwoffsets1,offsets2,offsets3,offsets4row: db2,4,6,8start:movax,cs movds,ax movbx,offsets movsi,offsetrow movcx,4 ok:movbh,0;第0页 movdh,[si];dh中放行号 movdl,0;dl中放列号 movah,2;2号子程序:放置光标 int10h movdx,[bx];ds:dx指向字符串要显示的字符串需要用$作为结束符 movah,9;在光标位置显示字符串 int21h incsi addbx,2 loopok movax,4c00h int21hcodeendsendstart端口端口的读写读写指令只有两条:in和outinal,60h从60h号端口读入一个字节out21h,al向21h端口写al注意,只能用al或者ax
movdx,3f8hinal,dxoutdx,alCMOSRAM芯片包含128个存储单元该芯片靠电池供电,断电后仍可继续工作,信息不丢失。时钟占用0-0dh单元,其余大部分单元保存系统配置信息,供系统启动时BIOS程序读取。该芯片有两个端口,70h和71h,cpu通过这两个端口读写CMOSRAM70h为地址端口,存放要访问的CMOSRAM单元的地址;71h为数据端口,存放从选定的CMOSRAM单元中读取的数据,或者要写入的数据。读2号单元:
assumecs:codecodesegmentstart:moval,2 out70h,al inal,71h movax,4c00h int21hcodeendsendstart向2号存储单元写入0:
assumecs:codecodesegmentstart:moval,2 out70h,al moval,0 out71h,al movax,4c00h int21hcodeendsendstartshr,shlshl逻辑左移,将一个寄存器或者内存单元中的数据向左移位,最后移出的一位写入CF。
moval,01001000bshlal,1执行后(al)=10010000B,CF=0如果移位位数大于1,必须将位数放在cl中。比如:
moval,01010001Bmovcl,3shlal,cl执行后(al)=10001000b,CF=0
计算(ax)=(ax)*10
编写int9例程,每次按下esc,改变显示字符颜色:
assumecs:codestacksegment db128dup(0)stackendscodesegmentstart:movax,0 moves,ax;es:0 movdi,0204h movax,cs movds,ax;ds:cs movsi,offsetint9 movcx,offsetint9end-offsetint9 cld repmovsb movax,stack movss,ax movsp,128 pushes:[9*4] popes:[200h] pushes:[9*4+2] popes:[202h] movax,204h moves:[9*4],ax movax,0 moves:[9*4+2],ax movax,4c00h int21h int9: pushax pushds pushcx pushbx inal,60h pushf calldwordptrcs:[200h] cmpal,3bh jneint9ret movax,0b800h moves,ax movbx,1 movcx,2000 s:incbyteptres:[bx] addbx,2 loops int9ret:popbx popcx popds popax iret int9end:nopcodeendsendstart实验15安装新的int9中断例程
assumecs:codestacksegment db128dup(0)stackendscodesegmentstart:movax,0 moves,ax;es:0 movdi,0204h movax,cs movds,ax;ds:cs movsi,offsetint9 movcx,offsetint9end-offsetint9 cld repmovsb movax,stack movss,ax movsp,128 pushes:[9*4] popes:[200h] pushes:[9*4+2] popes:[202h] movax,204h moves:[9*4],ax movax,0 moves:[9*4+2],ax movax,4c00h int21h int9: pushax pushes pushcx pushbx inal,60h pushf calldwordptrcs:[200h] cmpal,9eh jneint9ret movax,0b800h moves,ax movbx,0 movcx,2000 s:movbyteptres:[bx],'A' addbx,2 loops int9ret:popbx popcx popes popax iret int9end:nopcodeendsendstart直接定址表adb1,2,3,4,5,6,7,8bdw0start:moval,a[si];相当于moval,cs:0[si]moval,a[3];相当于moval,cs:0[3]movax,b;movax,cs:[8]movb,2;movwordptrcs:[8],2incb;incwordptrcs:[8]将a处的8个数据相加结果存到b处的双字中:
assumecs:codecodesegment adw1,2,3,4,5,6,7,8 bdd0 start:movsi,0 movcx,8 s:movax,a[si] adda[16],axadca[18],0 addsi,2loops movax,4c00h int21hcodeendsendstart 若将数据放在数据段,则必须assume
assumecs:code,ds:datadatasegment adb1,2,3,4,5,6,7,8 bdw0dataendscodesegmentstart:movax,data movds,ax movsi,0 movcx,8 s:moval,a[si] movah,0 addb,ax incsiloops movax,4c00h int21hcodeendsendstart 如果想在代码段中直接用数据标号访问数据,则需要用伪指令assume将标号所在的段和一个段寄存器联系起来。否则编译器在编译时无法确定标号的段地址在哪儿一个寄存器中。
datasegmentadb1,2,3,4,5,6,7,8bdw0cdda,bdataendsc处存储的两个双子为标号a的偏移地址和段地址,标号b的偏移地址和短地址。相当于
datasegmentadb1,2,3,4,5,6,7,8bdw0cdwoffseta,sega,offsetb,segbdataends应用:以16进制形式显示数字
assumecs:code,ds:datadatasegment tabledb'0123456789ABCDEF'dataendscodesegmentstart:movax,data movds,ax movax,0b800h moves,ax movdi,160*10+40 moval,0eh movah,al shrah,1 shrah,1shrah,1shrah,1 movbl,ah movbh,0 movah,table[bx] moves:[di],ah movah,02h moves:[di+1],ah andal,00001111b movbl,al movbh,0 movah,table[bx] moves:[di+2],ah movah,02h moves:[di+3],ahmovax,4c00h int21hcodeendsendstart 另一个应用,计算sin
movah,0int16h结果:(ah)=扫描码,(al)=ASCII码int16h中断例程的0号功能进行如下工作:
assumecs:codecodesegmentstart: movah,0 int16h cmpal,'r' jered cmpal,'g' jegreen cmpal,'b' jeblue red:movah,00000100b jmpshorts green:movah,00000010b jmpshorts blue:movah,00000001b s:movbx,0b800h moves,bx movbx,1 movcx,2000 s1:andbyteptres:[bx],11111000b ores:[bx],ah addbx,2 loops1 movax,4c00h int21hcodeendsendstart