文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
第 10 章:CALL 和 RET 指令
检测点 10.1
补全程序 ,实现从内存 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 ; CS,先入后出
push ax
mov ax,0000h ; IP
push ax
retf
code ends
end start
检测点 10.2
下面的程序执行后,ax 中的数值为多少?
内存地址 | 机器码 | 汇编指令 | ax | IP |
---|---|---|---|---|
1000: 0 | b8 00 00 | mov ax,0 | 0000h | 0003h |
1000: 3 | e8 01 00 | call s | 0006h | |
1000: 6 | 40 | inc ax | (该行未执行) | |
1000: 7 | 58 | s:pop ax | 0006h | 0008h |
检测点 10.3
下面的程序执行后,ax 中的数值为多少?
内存地址 | 机器码 | 汇编指令 | ax | bx | CS | IP | 栈 |
---|---|---|---|---|---|---|---|
1000: 0 | b8 00 00 | mov ax,0 | 0000h | ||||
1000: 3 | 9A 09 00 00 10 | call far ptr s | 1000h | 0008h | 0008h 1000h | ||
1000: 8 | 40 | inc ax | (该行未执行) | ||||
1000: 9 | 58 | s: pop ax | 0008h(IP) | 1000h | |||
add ax , ax | 0010h | ||||||
pop bx | 1000h(CS) | ||||||
add ax,bx | 1010h |
检测点 10.4
下面的程序执行后,ax 中的数值为多少?
内存地址 | 机器码 | 汇编指令 | ax | IP | 栈 |
---|---|---|---|---|---|
1000: 0 | b8 06 00 | mov ax,6 | 0006h | 0003h | |
1000: 3 | ff d0 | call ax | (跳转到 0006h) | 0005h | 0005h |
1000: 5 | 40 | inc ax | |||
1000: 6 | mov bp,sp | ||||
add ax, [bp] | 000Bh |
检测点 10.5
(1)下面的程序执行后,ax 中的数值为多少?(注意:用 call 指令的原理来分析,不要在 Debug 中单步跟踪来验证你的结论。对于此程序,在 Debug 中单步跟踪的结果,不能代表 CPU 的实际执行结果。)
assume cs:code
stack segment
dw 8 dup (0)
stack ends
code segment
start:
mov ax,stack ; ax 存储 stack 的段地址
mov ss,ax ; ss 指向 stack 段
mov sp,16 ; sp = 16,而 stack 是 8 字 == 16 字节,正好指向栈顶
mov ds,ax ; ds 指向 stack 段
mov ax,0 ; ax = 0000h
call word ptr ds:[0EH] ; 将 CS 和 IP 分别压栈,此时 IP 为该指令后的第一个字节
; 跳转地址为 ds:0E ~ ds:0F,而 ds 指向 stack 段,且栈顶恰好为第 16 个字节
; 因此该 call 指令即跳转到栈顶存储的 CS 和 IP 指向的位置
; 而栈顶存储的 IP 恰好指向的是下一条指令(inc ax)的地址
; 故这条指令执行完,直接执行下面的指令
inc ax ; ax = 0001h
inc ax ; ax = 0002h
inc ax ; ax = 0003h <- ax 最后的值
mov ax,4c00h
int 21h
code ends
end start
为什么不让使用 debug 来逐步调试?因为在执行到 CALL 指令时,显示 ds:[0eh]=065D(在我的环境中debug 后),ds:[0eh] 中的内容是中断的信息,并不是我们程序所希望的 0011H,它一下就 jmp 到 065D 的地址去了,而不是 CS:11 地址执行。
(2)下面的程序执行后, ax 和 bx 中的数值为多少?
assume cs:code
data segment
dw 8 dup (0)
data ends
code segment
start:
mov ax,data ; ax = data 段地址
mov ss,ax ; ss 指向 data 段
mov sp,16 ; sp = 16
mov word ptr ss:[0] , offset s ; ss:[0] 指向 s 的偏移地址
mov ss:[2],cs ; ss:[2] 指向段地址 CS
call dword ptr ss:[0] ; 分别将 CS 和 IP 压栈,sp = 12 = 0cH
; CS 位于 ss:[0eH],IP 位于 ss:[0cH]
; 入栈的 IP 为该指令后的第一个字节的偏移地址
;也即下面 nop 对应的地址
; 执行完跳转至 ss:[0],也即 s
nop ; 机器码 90,占据一字节
s:
mov ax,offset s ; ax = s 的偏移地址
sub ax,ss:[0cH] ; ax = ax - ss:[0cH],也即:
; ax = s 的偏移地址 - nop 的偏移地址,而 nop 为 1字节
; 故 ax = 0001h
mov bx,cs ; bx = CS 存储的段地址
sub bx,ss:[0eH] ; bx = CS 存储的段地址 - ss:[0eH]
; 而 ss:[0eH] 中恰好为 CS 地址
; 故 bx = 0000h
mov ax,4c00h
int 21h
code ends
end start
参考链接
- 汇编语言(王爽第三版)检测点10 - 筑基2017 - 博客园
实验 10 编写子程序
一、显示字符串
显示字符串是现实工作中经常要用到的功能,应该编写一个通用的子程序来实现这个功能。我们应该提供灵活的调用接口,使调用者可以决定显示的位置(行、列)、内容和颜色。
描述 | |
---|---|
名称 | show_str |
功能 | 在指定的位置,用指定的颜色,显示一个用 0 结束的字符串。 |
参数 | (dh)=行号(取值范围 0~24) (di)=列号(取值范围 0~79) (cl)=颜色 ds:si 指向字符串的首地址 |
返回 | 无 |
应用举例 | 在屏幕的 8 行 3 列,用绿色显示 data 段中的字符串。 |
参考链接
- 汇编语言(王爽第三版)实验10:编写子程序 - 筑基2017 - 博客园
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论