汇编学习--第九天
实验9 根据材料编程
注意:
在做第十章课后题时,发现个问题,最上面红框和下面两个红框,对偏移地址000h的叫法不同,我根据实际显示,es:000h叫0行0列(这一行不会在显示器上显示)
assume cs:codesg,ds:datasg,ss:stacksg datasg segment db 'welcome to masm!' db 02h,24h,71h;三种颜色 datasg ends stacksg segment db 16 dup (0) stacksg ends codesg segment ;datasg段地址 start: mov ax,datasg mov ds,ax ;stacksg段地址 mov ax, stacksg mov ss,ax mov sp,10h ;目标地址 mov ax,0b800h mov es,ax mov cx,3 mov di,10h;在datasg中的偏移量 mov bx,780h;表示第12行 ;第一层循环,3种颜色 s: mov si,0;在显示缓冲区中的偏移地址 mov ah,ds:[di] push cx push di mov di,0 mov cx,16 ;第二层循环,字符串 s0: mov al,ds:[di] mov es:[bx+si+64],al;低位存字符 mov es:[bx+si+64+1],ah;高位存属性 inc di add si,2 loop s0 pop di pop cx inc di add bx,0a0h loop s mov ax,4c00h int 21h codesg ends end start
要理解材料中的几个点:
- 1.每行可以表示80个字符,160字节
- 2.每行的偏移地址规律----起始偏移地址:行数 * 160 结束偏移地址:起始地址+159 (这里都是十进制表示,需要转换为十六进制)
- 3.属性字节格式,一共8位,每四位对应十六进制的字节的高位和低位。1表示有这个属性,0表示没有。
概括
这道题简单的说就是将字符数据和属性数据写入b800h(显示缓冲区),并居中显示。
分步解析
- 1.要居中,首先行居中为12行开始,根据上面的公式得到起始偏移地址780h,而下一行起始地址就是 原偏移地址+0a0h--0a0h为160字节;
- 2.列居中,字符串占16字符,总共80字符,还剩64字符,也就是128字节,字符串前后等距,为128/2=64字节,所以需要在偏移地址基础上加64
- 2.从自定义的datasg段中取字符串和属性数据,字符串写入低位:0b800h:[起始偏移地址+64] 属性写入高位:0b800h:[起始偏移地址+1+64]
第十章 CALL和RET指令
10.1 ret和retf
ret指令:使用栈中数据修改IP,实现近转移
retf指令:使用栈中数据修改CS和IP,实现远转移
执行ret相当于是pop IP,将栈顶元素作为IP值
执行retf相当于pop IP,pop CS,和ret类似
ret的应用
assume cs:codesg,ss:stacksg stacksg segment db 16 dup (0) stacksg ends codesg segment mov ax,4c00h int 21h start: mov ax,stacksg mov ss,ax mov sp,10h mov ax,0 push ax ret codesg ends end start
retf应用
assume cs:codesg,ss:stacksg stacksg segment db 16 dup (0) stacksg ends codesg segment mov ax,4c00h int 21h start: mov ax,stacksg mov ss,ax mov sp,10h mov ax,0 push cs push ax retf codesg ends end start
检测点 10.1
assume cs:codesg stacksg segment db 16 dup (0) stacksg ends codesg segment start: mov ax,stacksg mov ss,ax mov sp,10h mov ax,1000h push ax mov ax,0 push ax retf codesg ends end start
10.2 call指令
使用call指令进行两步:
- 1.将IP或CS和IP压入栈中
- 2.转移
call实现转移方法和jmp相似
10.3 依据位移进行转移的call指令
call + 标号
相当于执行
push ip
jmp near ptr 标号
检测点 10.2
ax=6
在读入指令call s时,IP首先自动+3(下一个指令偏移地址),所以入栈的数据为6,pop ax也就是ax=6
assume cs:codesg codesg segment start: mov ax,0 call s inc ax s: pop ax mov ax,4c00h int 21h codesg ends end start
10.4 转移的目的地址在指令中的call指令
call far ptr 标号
相当于执行
push CS
push IP
jmp far ptr 标号
检测点 10.3
assume cs:codesg codesg segment mov ax,4c00h int 21h start: mov ax,0 call far ptr s;入栈的IP为8,CS为1000h inc ax s: pop ax;ax=8 add ax,ax;ax=16 pop bx;bx=1000h add ax,bx;ax=1010h mov bx,0 push bx ret codesg ends end start
因为在我的代码中,入栈CS=076AH,IP=DH
所以
assume cs:codesg codesg segment mov ax,4c00h int 21h start: mov ax,0 call far ptr s;入栈的IP为dh,CS为076ah inc ax s: pop ax;ax=dh add ax,ax;ax=1ah pop bx;bx=076ah add ax,bx;ax=0784h mov bx,0 push bx ret codesg ends end start