[王爽老师汇编语言总结] 第9-11章

这三章都是跳转指令相关的

第9章 跳转指令的原理

  1. 何为转移指令?有哪几种类型?有什么区别?
    a. 修改IP或CS:IP的统称为转移指令
    b. 只修改IP是段内转移,如jmp ax,段内转移又有两个子类: 1.短转移,IP修改范围是[-128,127],比如jmp short 段名; 2.近转移,IP修改范围是[-32768,32767]
    c. 8086转移指令分为如下几类:1.无条件转移(如jmp); 2.条件转移(如jnz/jz/jna/ja等); 3. 循环指令(如loop); 4. 过程(iret/ret/call); 5.中断(如int 21h等)

  2. 为什么需要近转移和短转移两种类型的指令? 它们之间有何不同?
    a. “jmp short 标号” 功能为:(IP)=(IP)+8位位移

    1. 8位位移 = 标号处的地址 - jmp指令后的第一个字节地址
    2. short指明此处的位移为8位位移
    3. 8位位移的范围:[-128,127],用补码表示
    4. 8位位移由编译程序在编译时算出

    b. "jmp near ptr 标号"的功能为:(IP)=(IP)+16位位移

    1. 16位位移=标号处的地址-jmp指令后的第一个字节地址
    2. near ptr 指明此处为16位位移,进行段内近转移
    3. 16位位移范围:[-32768,32767],补码表示
    4. 16位位移由编译程序在编译时算出
  3. 介绍操作符offset
    a. offset s0就可以得到s0段的偏移地址

  4. 根据图中程序和其机器码介绍jmp short指令流程

assume cs:codesg
codesg segment
start: mov ax,0
       mov bx,0
       jmp short s
       add ax,1
 s:    inc ax
 codesg ends
 end start

在这里插入图片描述
a. (CS)=0BBDH,(IP)=0006H,CS:IP指向EB03(jmp short s的机器码)
b. 读取指令码EB03进入指令缓冲寄存器
c. (IP)=(IP)+所读取指令的长度=(IP)+2=0008H,CS:IP指向add ax,1
d. CPU执行指令缓冲器中的指令EB03,03就告诉了CPU将IP向后移动3个字节
e. 指令EB03执行后,(IP)=000BH,CS:IP指向inc ax
f. jmp short特点是:汇编编译后的机器码是根据CS:IP相对位置进行转移的(非常重要,如不熟悉详读书P177-180)

  1. 根据图中程序和其机器码介绍"jmp far ptr 标号"指令流程
    在这里插入图片描述

    a. “jmp far ptr 标号” 实现的是段间转移(远转移),(CS)=标号所在段的段地址,(IP)=标号在段中的偏移地址
    b. 根据CS:IP进行跳转

  2. 介绍转移地址在寄存器/内存中的jmp指令
    a. 寄存器指令格式: jmp 16位reg ,功能:(IP)=(16位reg)
    b. 内存格式:

    1. jmp word ptr 内存单元地址(段内转移) ;
      功能: 从内存单元地址处开始存放一个字,是转移的目的偏移地址
    2. jmp dword ptr 内存单元地址(段间转移)
      功能: 从内存单元地址处开始存放两个字,高地址的字是转移的目的段地址,低地址处是转移的目的偏移地址
      (CS)=(内存单元地址+2)
      (IP)=(内存单元地址)
  3. 理解检测点9.1(1)(2),要定义哪些数据,以及定义后为什么可以跳转?
    a. 9.1(1)随便定义一个db型的字符作为占位符或"db 16 dup (0)"都可以.
    b. 若选择一个占位符的方式,段会向16Bytes对齐,扩展为长度为16的.由于后续内容没有定义,为0.那么jmp word ptr [bx+1]就是相当于jmp cs:0

; 9.1(1)核心代码
data segment
    db 16 dup (0)
    ; 或者nop
data ends

start:
    mov ax, data
    mov ds, ax
    mov bx, 0
    jmp word ptr [bx+1]

; 9.2核心代码
data segment
    dd 12345678H
data ends

start:
    mov ax, data
    mov ds, ax
    mov bx, 0
    mov [bx], bx
    mov [bx+2], cs
    jmp dword ptr ds:[0]
  1. 介绍jcxz指令
    a. 指令格式: jcxz 标号
    b. 当(cx)=0时,(IP)=(IP)+8位位移;
    c. 8位位移=标号处地址-jcxz指令后的第一个字节地址; [-128,127], 补码; 编译时算出;
    d. 相当于 if ((cx)==0) jmp short 标号;
    e. e.g. 找到2000H段中第一个值为0的字节,并将它的偏移地址存在dx中
    mov ax, 2000H
    mov ds, ax
    mov bx, 0
    s:
        mov cx, [bx]
        jcxz ok
        inc bx
        jmp short s
    ok:
        mov dx, bx
  1. 介绍loop指令
    a. loop是循环指令,所有循环指令都是短转移,IP范围[-128,127]
    b. loop 标号((cx)=(cx)-1,如果(cx)!=0,转到标号处执行)
    c. (cx)=(cx)-1; 如果(cx)!=0,(IP)=(IP)+8位位移
    d. loop 标号相当于: (cx)–; if((cx)!=0) jmp short 标号;
    e. e.g. 找到2000H段中第一个值为0的字节,并将它的偏移地址存在dx中
start:
    mov ax, 2000h
    mov ds, ax
    mov bx, 0
s:
    mov cl, [bx]
    mov ch, 0
    inc cx
    inc bx
    loop s

ok:
    dec bx
    mov dx, bx
  1. 根据位移进行转移有啥意义和优势?
    a. 绝对地址转移对地址的值有严格的限制,并且如果程序修改那么绝对地址也可能变
    b. 相对位移不存在这个问题
    c. 如果jmp short 超出了[-128,127]字节的限制,那么编译器会报错; 同理,jmp near超出也会
    d. 而使用绝对地址跳转编译时无法检测,故不会报错,需要编程者来确保跳转的位置正确

  2. 实验8,好题:分析如下程序,是否可以正确返回
    在这里插入图片描述

    a. 实验8中的程序会把"jmp short s1"拷贝到两个字节的nop中.为什么可以拷贝成功?因为jmp short s1是两个字节
    b. 那么它拷贝后,实际的代码是jmp short s1吗?不是.因为jmp short是根据机器码的值进行相对转移的
    c. 所以它实际是向前转移 **s1代码段的长度",也就是转移到codesg刚开始的位置
    d. 根据上面三点的分析,最后该程序会执行"mov ax,4c00h ; int 21h",故会成功返回

  3. 实验9,寻址练习
    a. bx作为行索引,si作为列索引,其实这两也可以合并在一起,但是影响可读性

assume cs:code

data segment
    db 'welcome to masm!'
    db 2H, 24H, 71H
data ends

stack segment
    db 16 dup (0)
stack ends

code segment
start:
    mov ax,data
    mov ds,ax
    mov bx,6e0h ; (bx) = line index
    mov ax,0b800h
    mov es,ax
    mov cx,3
    mov bp,0

s:
    push cx
    mov si,40h ; (si) = column index

    mov cx,16 ; 'welcome to masm!' length=16
    mov di,0
    copy_str:
        mov al,ds:[di]
        mov es:[bx][si],al
        mov al,ds:[bp][16]
        mov es:[bx][si].1,al
        add si,2
        inc di
        loop copy_str

    inc bp
    add bx, 0A0h
    pop cx
    loop s

    mov ax, 4c00h
    int 21h

code ends
end start

在这里插入图片描述

第10章 CALL和RET指令

  1. 介绍ret指令
    a. ret指令用栈中的数据,修改IP内容,实现近转移
    b. 流程: (IP)=((SS)*16+(SP); (SP)=(SP)+2
    c. 相当于: pop IP
	mov ax,4c00h
	int 21h
start:
    mov ax, stack
    mov ss, ax
    mov sp, 16
    mov ax, 0
    push ax
    ret
  1. 介绍retf指令
    a. retf指令用栈中的数据,修改CS和IP的内容,实现远转移
    b. 流程:(IP)=((SS)*16+(SP)) ; (SP)=(SP)+2 ; (CS)=((SS)*16 + (SP)) ; (SP)=(SP)+2
    c. 相当于:pop IP ; pop CS
    mov ax, 4c00h
    int 21h
start:
    mov     ax, stack
    mov     ss, ax
    mov     sp, 16
    mov     ax, 0
    push    cs
    push    ax
    retf
  1. 介绍call指令
    a. 将当前的IP或CS:IP压入栈中 ; 转移
    b. call指令不能实现短转移, call指令实现的转移方法和jmp指令原理相同

  2. 根据位移进行转移的call指令
    a. call 标号(当前的IP压栈后,转到标号处执行命令)
    b. 流程:

    (SP)=(SP)-2
    ((SS)*16+(SP))=(IP)
    (IP)=(IP)+16位位移 ; 16位位移=标号处的地址-call指令后的第一个字节的地址,范围是[-32768,32767],补码,编译时算出

    c. 相当于:

    push IP
    jmp near ptr 标号

    d. 程序执行后ax是什么?
    在这里插入图片描述
    答案是:6

  3. 转移的目的地址在指令中的call指令
    a. call fat ptr 标号 -> 实现段间转移
    b. 流程为:

    注:(CS)=标号所在段的段地址,(IP)=标号在段中的偏移地址
    (SP)=(SP)-2
    ((SS)*16+(SP))=(CS)
    (SP)=(SP)-2
    ((SS)*16+(SP))=(IP)

    c. 相当于:

    push CS
    push IP
    jmp far ptr 标号

    d. 程序执行后ax/bx是什么?
    在这里插入图片描述
    答案是:(ax)=1010,(bx)=1000

  4. 转移的目的地址在寄存器中的call指令
    a. 格式: call 16位reg
    b. 功能:

    (SP)=(SP)-2
    ((SS)*16+(SP))=(IP)
    (IP)=(16位reg)

    c. 相当于:

    push IP
    jmp 16位reg

    d. 程序执行后ax是什么?
    在这里插入图片描述
    答案是:(ax)=0bh. 这道题并不好思考,你需要知道,[bp]是ss:[bp],所以sp的值不重要,重要的是ss:[sp]的值是多少.根据该指令的功能,可知此时ss:[sp]=ss:[bp]=5,所以ax存储的值多少就知道了.

  5. 转移的目的地址在内存中的call指令
    a. call word ptr 内存单元地址

    push IP
    jmp word ptr 内存单元地址

    b. 下面的程序执行后(IP)=?,(SP)=?

    mov sp,10h
    mov ax,0123h
    mov ds:[0],ax
    call word ptr ds:[0]
    

    (IP)=0123h,(sp)=0eh

    c. call dword ptr 内存单元地址

    push CS
    push IP
    jmp dword ptr 内存单元地址

    d. 下面的程序执行后(CS)=?,(IP)=?,(SP)=?

    mov sp, 10h
    mov ax, 0123h
    mov ds:[0], ax
    mov word ptr ds:[2], 0
    call dword ptr ds:[0]
    

    (cs)=0,(ip)=0123h,(sp)=0ch

    e. 完成下面两题, 这两题考察call指令的原理
    在这里插入图片描述
    在这里插入图片描述

第一题: (ax)=3, 但是我没有理解为什么在Debug中单步跟踪的call跳转的位置和理论值不一样
第二题: (ax)=1,(bx)=0

  1. call和ret配合使用实现子程序调用
    a. P196 10.7 具体例子详细分析

  2. 如何进行批量数据传递?
    a. 通过内存开辟一块空间,将要传递的参数放在空间中,然后子程序去使用
    b. 通过push/pop的方式通过栈传递(其实本质上也是内存空间传递)
    c. 基本模式:

    子程序开始:
    子程序中使用的寄存器入栈
    子程序内容
    子程序中使用的寄存器按入栈相反顺序出栈
    返回(ret/retf)

    d. 下面是一个通过内存空间传递参数的例子

data segment
    db 'word', 0
    db 'unix', 0
    db 'wind', 0
    db 'good', 0
data ends

code segment
start:
    mov ax, data
    mov ds, ax
    mov bx, 0
    mov cx, 4
s:
    mov si, bx
    mov dx, cx
    call capital
    add bx, 5
    mov cx, dx
    loop s
    mov ax, 4c00h
    int 21h
capital:
    push cx
    push si
change:
    mov cl, [si]
    mov ch, 0
    jcxz ok
    and byte ptr [si], 11011111b
    inc si
    jmp short change
ok:
    pop si
    pop cx
    ret
code ends

实验10
注意点:实验10的1,2,3要做到模块化,否则课程设计1需要用到1,2,3时,用起来会非常痛苦.
1.

assume cs:code

data segment
    db 'Welcome to masm!', 0
data ends

code segment

start:
    mov dh, 8
    mov dl, 3
    mov cl, 2
    mov ax, data
    mov ds, ax
    mov si, 0
    call show_str
    mov ax, 4c00h
    int 21h

; dh=line, dl=column, cl=color
show_str:
    push si
    push di
    push es
    push ax
    push cx
    mov si,0
    mov di,0
    mov cx,0b800h
    mov es,cx
    mov cl,dh
    mov ch,0

line_offset:
    add di,160
    loop line_offset

    mov cl,dl
column_offset:
    add di,2
    loop column_offset

    pop cx
    mov al,cl
    mov ch,0
show:
    mov cl,ds:[si]
    mov es:[di],cl
    mov es:[di].1,al
    jcxz show_str_end
    add di, 2
    inc si
    jmp show

show_str_end:
    pop ax
    pop es
    pop di
    pop si
    ret

code ends
end start

在这里插入图片描述

assume cs:code
stack segment
    dw 16 dup (0)
stack ends

code segment
start:
    mov ax, 4242h ; 被除数低16
    mov dx, 0fh ; 被除数高16
    mov cx, 0ah ; 除数
    call divdw
    mov ax, 4c00h
    int 21h

divdw:
    push bx
    push si

    mov bx, ax ; store ax register in bx
    mov ax, dx
    mov dx, 0
    div cx ; int(h/n)
    mov si, ax ; save int(h/n) in si

    mov ax, bx
    div cx

    mov cx, dx
    mov dx, si

    pop si
    pop bx
    ret
code ends
end start

计算结果:
在这里插入图片描述

模块化子程序是关键,利用push/pop指令做到子程序调用间的寄存器互不干扰

assume cs:code
data segment
    db 16 dup (0)
data ends
stack segment
    db 16 dup (0)
stack ends
code segment
start:
    mov ax,stack
    mov ss,ax
    mov sp,16

    mov ax,12666
    mov bx,data
    mov ds,bx
    mov si,0
    call dtoc

    mov dh,8
    mov dl,3
    mov cl,2
    call show_str

    mov ax,4c00h
    int 21h

; ax:the number which convert to string,16 bits
; ds:data buffer
; si: ds offset
; return: set data buffer
dtoc:
    push cx
    push dx
    push bx
    push bp
    push ax

    mov bx,10
    mov dx,0 
    mov bp,0 ; counter of number length

    getnrlen:
        mov cx,10
        call divdw
        inc bp
        cmp dx,0
        jnz getnrlen
        cmp ax,0
        jnz getnrlen

dtoc0:
    pop ax
    mov bx,data
    dec bp

    dtoc1:
        mov cx,10
        call divdw
        add cl,48
        mov ds:[bp],cl
        dec bp
        cmp dx,0
        jnz dtoc1
        cmp ax,0
        jnz dtoc1

    pop bp
    pop bx
    pop dx
    pop cx
    ret

; (ax): dword data low 16 bits
; (dx): dword data high 16 bits
; (cx): divior
; return: (dx): high 16 bits, (ax): low 16 bits, (cx)=reminder
divdw:
    push bx
    push si

    mov bx, ax ; store ax register in bx
    mov ax, dx
    mov dx, 0
    div cx ; int(h/n)
    mov si, ax ; save int(h/n) in si

    mov ax, bx
    div cx

    mov cx, dx
    mov dx, si

    pop si
    pop bx
    ret

; data:show string buffer
; dh=line, dl=column, cl=color
show_str:
    push si
    push di
    push es
    push ax
    push cx
    mov si,0
    mov di,0
    mov cx,0b800h
    mov es,cx
    mov cl,dh
    mov ch,0

line_offset:
    add di,160
    loop line_offset

    mov cl,dl
column_offset:
    add di,2
    loop column_offset

    pop cx
    mov al,cl
    mov ch,0
show:
    mov cl,ds:[si]
    mov es:[di],cl
    mov es:[di].1,al
    jcxz show_str_end
    add di, 2
    inc si
    jmp show

show_str_end:
    pop ax
    pop es
    pop di
    pop si
    ret
code ends
end start

在这里插入图片描述

第11章 标志寄存器

  1. 标志寄存器作用和结构
    a. 存储相关指令的执行结果
    b. 为CPU执行相关指令提供行为依据
    c. 控制CPU的相关工作方式
    在这里插入图片描述

  2. ZF标志位
    a. 记录add/sub/mul/div/inc/or/and等算术或逻辑运算结果,为0时ZF=1,否则=0

  3. PF标志位
    a. 记录add/sub/mul/div/inc/or/and等算术或逻辑运算后所有bit位中1的个数是偶数时PF=1,否则PF=0

  4. SF标志位
    a. 符号标志位,SF=1则是负数,=0是非负

  5. CF标志位
    a. 记录进位(add)或借位(sub)
    b. 对无符号数运算有意义的标志位,其中inc/loop不会影响cf位

  6. OF标志位
    a. 发生溢出,OF=1,否则OF=0
    b. 对有符号数运算有意义的标志位

  7. adc指令
    a. 带cf进位加法指令
    b. adc ax,bx => (ax)=(ax)+(bx)+CF

  8. 两个128位数据相加的子程序
    a. 128位需要8个字单元
    b. 为什么不能将4个inc指令用两个add si/di, 2进行替换? --> 因为inc和loop不影响cf位,但是add影响cf位

add128:
        push ax
        push cx
        push si
        push di
        sub ax,ax ; clear CF
        mov cx,8
        s:
                mov ax,ds:[si]
                adc ax,ds:[di]
                mov ds:[si],ax
                inc si
                inc si
                inc di
                inc di
                loop s
        pop di
        pop si
        pop cx
        pop ax
        ret
  1. sbb指令
    a. 带借位减法指令 => sbb ax,bx => (ax)=(ax)-(bx)-CF

  2. cmp指令
    a. 不保存结果,仅根据计算结果对标志寄存器进行设置
    b. cmp ax, ax => (ax)-(ax), zf=1, pf=1, sf=0, cf=0, of=0
    c. p225

  3. 检测比较结果的条件转移指令
    在这里插入图片描述

  4. DF标志
    a. 控制每次操作后si/di的增减
    b. df=0, si/di递增 ; df=1, si/di递减

  5. movsb/movsw指令
    a. movsb相当于执行了:

    ((es)*16+(di))=((ds)*16+(si))
    if df = 0, then (si) = (si) + 1 , (di) = (di) + 1
    if df = 1, then (si) = (si) - 1, (di) = (di) - 1 ; movsw 则是 +2/-2

    b. rep movsb/movsw 根据cx的值重复执行后面的串传送指令,每执行一次movsb指令si和di都会递增或递减指向后一个或前一个单元,相当于:

    s: mov sb
       loop s
    

    c. 递增/递减则有df控制,而cld/std可以对df进行设置:

    cld: 将标志寄存器df=0
    std: 将标志寄存器df=1

    d. 逆向传送,从F000:FFFF拷贝最后16个单元到data:000F

mov ax,0f000h
mov ds,ax
mov si,0ffffh
mov ax,data
mov es,ax
mov di,15
mov cx,16
std
rep movsb
  1. pushf和popf
    a. 将标志寄存器压栈和弹出
    b. 压入的栈是ss吗?

  2. 标志寄存器在Debug中的表示
    在这里插入图片描述
    实验11

assume cs:codesg

datasg segment
	db "Beginner's All-purpose Symbolic Instruction Code.", 0
datasg ends

codesg segment
begin:
	mov ax,datasg
	mov ds,ax
	mov si,0
	call letterc

	mov ax,4c00h
	int 21h
letterc:
	mov cx,0
	mov cl,ds:[si]
	jcxz lettercend
	cmp cx,'a'
	jb again
	cmp cx,'z'
	ja again
	and cl,011011111b
	mov ds:[si],cl
again:
	inc si
	jmp letterc
lettercend:
	ret
codesg ends
end begin

在这里插入图片描述

习题:
11.2/11.4要做,增加对标志寄存器的理解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值