- [gsyangchao] 继续努力啊! 10/09 11:42
- [游客] 下面的程序执行后,ax和bx中的数值为多少? (10.5的第二题) AX的值应该为1 NO 07/06 11:02
- [gsyangchao] 恩,很有问题。。。当时昏了没注意 03/15 21:29
- [游客] 看你的截图中,最后一列的数据 有些好像不大对啊? 呵呵! 03/11 11:19
- [游客] 怎么不发了啊...... 03/09 07:35
- [游客] 很受启发! 03/03 17:01
- [游客] 好强啊! 03/02 07:15
- [miaozaoyang] 哇,你好强啊! 都学这么多了! 我还在学汇编呢! 呵呵 厉害。。。 02/28 00:19
- [游客] 好像有排列、组合的问题。呵呵。好熟悉。 02/27 10:00
- [游客] 很好,继续加油啊! 02/24 11:30
- [njutyangxiao] 请问你在做第十七章时你的dos环境是如何搭配的,我发现在vmware下安装的dos无法共享文件夹,在 09/24 09:18
- [miaozaoyang] 我发现你学习的速度太快了! 由衷的佩服。。。。。。。 呵呵呵 02/02 16:20
- [miaozaoyang] 对,多谢你的提点了! 呵呵! 01/25 14:29
[2009-01-30 01:20] 第十章call和ret指令
补全程序,实现从内存1000:0000处开始执行指令。
assume cs:code
stack segment
db 16 dup (0)
stack ends
code segment
start:
mov ax,stack
mov ss,ax
mov sp,16
mov ax,1000H
----------
push ax
mov ax,0000H
----------
push ax
retf
code ends
end start
检测点10.2
下面的程序执行后,ax中的数值为多少?
内存地址 机器码 汇编指令
1000:0 b8 00 00 mov ax,0
1000:3 e8 01 00 call s
1000:6 40 inc ax
1000:7 58 s:pop ax
答:执行完call s后IP变为0006,push IP 后pop ax,所以ax的值为0000 0006。
检测点10.3
下面的程序执行后,ax中的数值为多少?
内存地址 机器码 汇编指令
1000:0 b8 00 00 mov ax,0
1000:3 9A 09 00 00 10 call far ptr s
1000:8 40 inc ax
1000:9 58 s:pop ax
add ax,ax
pop bx
add ax,bx
答:执行完call far ptr s后IP变为0008,push CS,push IP后
pop ax ;ax=0000 0008
add ax,ax ;ax=0000 0010
pop bx ;bx=0000 1000
add ax,bx ;ax=0000 1010
检测点10.4
下面的程序执行后,ax中的数值为多少?
内存地址 机器码 汇编指令
1000:0 b8 00 00 mov ax,6
1000:2 ff d0 call ax
1000:5 40 inc ax
1000:6 mov bp,sp
add ax,[bp]
答: mov ax,6 ;ax=0000 0006
call ax ;IP=0005 ; PUSH IP ; jmp ax ;
mov bp,sp
add ax,[bp] ;也就是add ax,[sp];而[sp]=0000 0005
;ax=0000 000B
检测点10.5
(1) 下面的程序执行后,ax中的数值为多少?(注意:用call指令的原理来分析,
不要在Debug中单步跟踪来验证你的结论。对于此程序,在Debug中单步跟踪的结
果,不能代表CPU的实际执行结果)
assume cs:code
stack segment
dw 8 dup (0)
stack endsd
code segment
start:
mov ax,stack
mov ss,ax ;stack段段地址存入ss
mov sp,16
mov ds,ax ;stack段段地址存入ds
mov ax,0 ;将ax置0
call word ptr ds:[0EH] ;IP=下一条指令第一字节
;然后PUSH IP后sp=0EH
;jmp word ptr ds:[0EH]
inc ax ;ax=ax+1=0000 0001
inc ax ;ax=0000 0002
inc ax ;ax=0000 0003
code ends
end start
(2)下面的程序执行后,ax和bx中的数值为多少?
assume cs:code
data segment
dw 8 dup (0)
data ends
code segment
start:
mov ax,data
mov ss,ax
mov sp,16 ;data段段地址送入ss,置sp为10H
mov word ptr ss:[0],offset s ;将s段起始处偏移量送入ss:[0]
mov ss:[2],cs ;code段段地址送入ss:[2]
call dword ptr ss:[0] ;IP='nop'指令第一字节
;PUSH CS后sp=0EH,ss:[0EH]=(CS)
;PUSH IP后sp=0CH,ss:[0CH]=(IP)
;(CS)不变,(IP)=s段指令第一字节
nop
s:
mov ax,offset s ;将s段起始处偏移量送入ax
sub ax,ss:[0CH] ;用ax和ss:[0CH]相减,ax=0H
mov bx,cs ;将code段段地址cs送入bx
sub bx,ss:[0eH] ;用bx和ss:[0EH]相减,bx=0H
code ends
end start
实验10 编写子程序
1.显示字符串
名称:show_str
功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串。
参数:(dh)=行号(取值范围0~24),(dl)=列号(取值范围0~79),
(cl)=颜色,ds:si指向字符串的首地址
返回:无
show_str:
push ax
push bx
push cx
push dx
push si ;入栈,保护现场
mov ax,0B800H
mov es,ax ;显示器缓冲区段地址
mov si,0 ;si指向data段字符
dec dh
mov al,160
mul dh ;(dh-1)*160
mov bx,ax
dec dl
mov al,2
mul dl ;(dl-1)*2
add bx,ax ;(dh-1)*160+(dl-1)*2=对应显存起始地址
mov ah,cl ;将颜色属性送入高位
change:
mov cl,ds:[si] ;将要显示的字符送入cl中
mov ch,0
jcxz show_strok ;碰到符'0'结束
mov al,cl ;将字符送入低位,整个信息在ax中
mov es:[bx],ax ;存入显存
inc si
add bx,2
jmp short change
show_strok:
pop si
pop dx
pop cx
pop bx
pop ax
ret
2.解决除法溢出的问题
名称:divdw
功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为
dword型。
参数:(ax)=dword型数据的低16位
(dx)=dword型数据的高16位
(cx)=除数
返回:(dx)=结果的高16位,(ax)=结果的低16位
(cx)=余数
divdw:
push si
push di ;保护现场
mov si,ax ;将X的低16位L存入si
mov ax,dx ;将X的高16位H存入ax
mov dx,0
div cx ;(H/N)故需要H的低16位在ax,高16位在dx
;(ax)=int(H/N) (dx)=rem(H/N)
mov di,ax ;将int(H/N)存入di中
mov ax,si
div cx ;(ax)=[rem(H/N)*65536+L]/N的商,(dx)=其余数
mov cx,dx ;将余数存入cx中
mov dx,di ;将int(H/N)作为商的高16位存入dx
;即int(H/N)*65536
pop di
pop si
ret
3.数值显示
名称:dtoc
功能:将word型数据转变为表示十进制数的字符串,字符串以0为结尾符。
参数:(ax)=word型数据
ds:si指向字符串的首地址
返回:无
dtoc:
push ax
push cx
push si
push di
push dx
mov di,sp ;将当前栈指针的值送入di保存
;用来取数据时的是否取完
divide:
mov dx,0 ;为防止溢出,进行16位除法
mov cx,10 ;除数为10
div cx ;(dx)=rem(ax/10) (ax)=int(ax/10)
push dx ;将余数入栈
mov cx,ax ;将商移入cx用来判断是否求完
jcxz convert ;(cx)=0表示已求完,进行转换
jmp short divide ;没有求完则,商作为下一次的被除数
convert:
mov cx,di ;将数据入栈前栈指针的值送入cx与当前栈指针比较
sub cx,sp
jcxz dtocok ;如果数据全部出栈,则convert完成,没完成继续出栈
pop ax ;余数仅为0~9所以可以用8位寄存器表示出来
add al,30H ;将余数加30H变为ASC码
mov ds:[si],al ;字符串送入首地址
inc si
jmp short convert
dtocok:
mov ds:[si],0
pop dx
pop di
pop si
pop cx
pop ax
ret
(1)各子程序均带入程序中测试正确。
(2)divide子程序中我用15266吧好像是,反正是挺大一个数执行后处了错,但不是除法溢出,好像是MS-DOS的保护措施,估计是子程序中没开辟栈空间,系统自动开辟的用的太都了就溢出了吧,与子程序本身没关,其他数据(比12666小的)显示正常。
(3)我个人觉得子程序这东西既然叫子程序,你里面所有用到的寄存器,除了要求返回的寄存器您可以在一开始不保存,其他寄存器都应该PUSH,保存起来,不能因为1个子程序就修改了某些寄存器的值。
(4)子程序,就应该老实一点,别人传了什么参数进来,功能是怎么返回的一定要明确,不能给了你SI是字符串首地址,你来个逆序输出。
[ younggay 发表于 2009-02-02 17:00 ]
ax的值为0000 0006
ax=0000 000B
------
ax可是16位的,你这么一些,好像...
[ younggay 发表于 2009-02-02 17:03 ]
10.5的第2题
sub ax,ss:[0CH] ;用ax和ss:[0CH]相减,ax=0H
===================
这里的ax的值不对,ss:[0cH]中保存的是call指令下面的指令的ip地址,而s可是call后面的第二条指令哟,没看到那个nop么?
[ younggay 发表于 2009-02-02 17:07 ]
(2)divide子程序中我用15266吧好像是,反正是挺大一个数执行后处了错,但不是除法溢出,好像是MS-DOS的保护措施,估计是子程序中没开辟栈空间,系统自动开辟的用的太都了就溢出了吧,与子程序本身没关,其他数据(比12666小的)显示正常。
==============
我觉得应该是你程序的问题。再研究研究吧。即使处理32位的数据,该算法也应该没有问题的。
[ 游客 发表于 2010-07-06 11:02 ]
下面的程序执行后,ax和bx中的数值为多少? (10.5的第二题)
AX的值应该为1 NOP指令占了一个字