实验8:分析一个奇怪的程序
assume cs:codesg
codesg segment
mov ax, 4c00H
int 21H
start: mov ax, 0
s: nop
nop
mov di, offset s
mov si, offset s2
mov ax, cs:[si]
mov cs:[di], ax
s0: jmp short s
s1: mov ax, 0
int 21H
mov ax, 0
s2: jmp short s1
nop
codesg ends
end start
分析下面程序,在运行前思考:这个程序可以正确返回吗?运行后思考:为什么是这样的结果?通过这个程序加深对相关内容的理解.
解:
- 程序根据从start处开始执行。nop命令占用一个字节,会被CPU执行,只是什么都不做(No operation)。
- nop下 - s0前的四条指令意为:将s2处的指令的机器码,注意是机器码,是机器码值存储到s处的两个字节(两个nop)。
- 程序执行到s0处时,jmp跳转到s处,执行。
- 执行的是什么?s2处的指令jmp short s1的机器码
- 机器码是多少?即为位移量值。即IP寄存器需要根据此进行变更值,跳转指定位置执行的代码。
- 位移值是多少?-10(补码形式存储),00001010(源码)>> 11110101(取反)>> 11110110(加一)>> F6H(转16进制后)
- 如何计算出的-10?需要跳转的标号处的指令的偏移量 - jmp指令后的第一个字节的偏移量。
- 为什么是减去jmp命令后的一个字节的偏移量?回顾第二章:2.10节的指令的执行流程(下面有总结描述),IP寄存器的值增加指令机器码数据的长度数 发生在执行指令前。所以执行EB(jmp指令对应的机器码)跳转时,IP已经增加了。故要以jmp指令后的一个字节的偏移量为基准,计算位移值。
- 执行后IP指向了哪里?代码段的第一行:mov ax, 4c00H。
- 位移量为负数时,也是从jmp指令后的一个字节的偏移量为基准,进行移动吗?是的,位移量多加上jmp指令的长度呗。
指令的执行流程:
- 根据指令地址通过地址加法器计算出20位内存地址
- 通过20位地址总线找到存需要执行的指令的机器码的内存存储单元
- 通过数据总线将指令的机器码写入CPU的指令缓冲器
- IP寄存器的值增加指令机器码数据的长度数
- 执行机器码
- 回到第一步再次执行流程
实验9:根据材料编程
编程:在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串:“welcome to masm!”
实现代码:
assume cs:codesg,ds:data
data segment
db 'welcome to masm!' ;16b
db 02H,24H,71H ; 绿色:00000010(02H);绿底红色:00100100(24H);白底蓝色:01110001(71H)
codesg segment
start:
; 输入数据源
mov ax,data
mov ds,ax
; 显存 & 写入的内存位置``
mov ax,0B800H
mov es,ax
mov bx,1824 ; 1760 + 64
; 字符的属性数据位置
mov si,16
mov cx,3
count:
push cx
mov cx,16
mov di,0
write:
; read char
mov al,ds:[di]
; write char
mov es:[bx],al
; write char attributes
mov al,ds:[si]
mov es:[bx+1],al
inc di
add bx,2
loop write
inc si
add bx,128
pop cx
loop count
mov ax, 4c00H
int 21H
codesg ends
end start
总的来说,除了阅读材料外,没有新的内容。巩固数据的内存定位,与寄存器的使用分配。
复习下已学的寄存器的不同用途(未学:bp、psw):
- ds/es段寄存器用于读取内存数据。
- bx/di/si可以参与内存定位,作为偏移量,其他的寄存器不可。
- 循环控制只能使用cx。
- 除法运算时只会用到ax/dx。
- ss段寄存器存储着栈的内存起始位置,sp寄存器记录着push存储数据时的偏移量。
- cs段寄存器存储需要的执行机器码的内存起始位置,ip寄存器存储着下一条执行机器码的偏移量。
2022.04.30补充
关于bp寄存器:
- bp也可以参与内存定位。bx、bp、si、di可以单独,或者以4中组合的形式出现在[]中
- [bx+si] | [bx+di] | […+idata]
- [bp+si] | [bp+di] | […+idata]
- 错误的:[si+di] | [bx+bp]
- 若在[]中使用bp寄存器,且没有显示的给出段地址,则段地址默认在ss中。就如[] 中使用bx寄存器,段地址默认在ds中。例:
- mov ax,[bp] = (ax) = ((ss)*16 + (bp))
- mov ax,[bp+si] = (ax) = ((ss)*16 + (bp) + (si))
- mov ax,[bp+si+idata] = (ax) = ((ss)*16 + (bp) + (si) + (idata))