为体现入栈的重要性,这里结合了实验9的部分内容,在缓冲区写入了三行数据。思路和实验9差不多,如果没有“检测到0则结束输出”这个要求,应该不需要用到call、jcxz、ret这三个指令。
assume cs:code
data segment
db 'welcome to masm!',0 ;0表示结束
db 'hello world!!!!!',0
db 'test!',0
data ends
;彩色模式段在0b800,使用es段寄存器存储
code segment
start:
;第8行第3列,一行160字节,一列1个字节
mov dh,8 ;行
mov dl,2 ;列
mov ax,data
mov ds,ax ;ds地址
mov ax,0b800h
mov es,ax ;彩色模式段
mov si,0 ;偏移地址
mov cx,3 ;3行,故循环3次
show_addr:
mov al,160
mul dh ;计算结果存储到al
mov bx,ax
mov al,2
mul dl
add bx,ax ;160*8+2*8即为最终的地址
mov al,2 ;字符属性
s: push cx ;cx入栈
call write_str ;ip入栈
pop cx ;cx出栈
add bx,128 ;下一行
inc si ;读取下一个字符,该字符为下一行字符串的第一个字符
loop s ;循环,cx-1
mov ax,4c00h
int 21h
;ds和es都确认了,ds存储了字符,现在需要将ds的字符存入es所指的地址。其中,一个字符两个字节,低位是ascii值,高位是字符属性。
;按照该逻辑,最终的效果应为"mov es:[bx+di],ds:[si]"
;第一次指令结束后需要进行循环,此时di+2,si+1。
write_str:
mov cl,ds:[si] ;读取内存中地址所存储的字符
jcxz go ;为0则跳转到go
mov es:[bx+di],cl
mov es:[bx+di+1],al ;存储字符属性
add bx,2
inc si ;循环结束后,si指向了字符串的最后一个字符
jmp short write_str ;此时cx作为中转数据的寄存器,不宜使用loop指令
go: ret ;ip出栈,跳转到ip所在地址
code ends
end start