王爽汇编语言个人总结(二)

第7章 <更灵活的定位内存地址的方法>

and 和 or 指令

and指令:逻辑与指令,按位进行与运算
mov al,01100011B
and al,00111011B
执行后:al = 00100011B

or指令: 逻辑或指令,按位进行或运算
mov al,01100011B
or al,00111011B

ASCII码

我个人是喜欢记住48 65 97这三个数字

48对应0
65对应A
97对应a

以字符形式给出的数据
assume cs:code,ds:data
data    segment
    db  'unix'
    db  'foRK'
data    ends
code    segment
start:  mov al,'a'
        mov bl,'b'
        mov ax,4c00h
        int 21h
code    ends
end     start
DW 是定义2字节空间的意思。DW属于汇编的一个伪指令,DW定义字类型变量,一个字数据占2个字节单元,读完一个,偏移量加2。

DB定义字节类型变量,一个字节数据占1个字节单元,读完一个,偏移量加1。

DD定义双字类型变量,一个双字数据占4个字节单元,读完一个,偏移量加4。
很有意思的大小写转换
assume  cs:codesg,ds:datasg
datasg  segment
    db  'Hello'
    db  'Study'
datasg  ends  
codesg  segment
    start:  mov ax,datasg
            mov ds,ax
            mov bx,0
            mov cx,5
        s:  mov al,ds:[bx]
            and al,11011111B
            mov ds:[bx],al
            inc bx
            loop s

            mov cx,5

        g:  mov al,ds:[bx]
            or  al,00100000B
            mov ds:[bx],al
            inc bx
            loop g

            mov ax,4c00h
            int 21h
cosesg  ends
end start
[bx+idata]

mov ax,[bx+200] -> (ax) = ((ds)*16 + (bx) + 200)
改进上述代码

assume  cs:codesg,ds:datasg
datasg  segment
    db  'Hello'
    db  'Study'
datasg  ends  
codesg  segment
    start:  mov ax,datasg
            mov ds,ax
            mov bx,0
            mov cx,5
        s:  mov al,ds:[bx]
            and al,11011111B
            mov ds:[bx],al
            mov al,ds:[bx]
            or  al,00100000B
            mov ds:[bx],al
            inc bx
            loop s

            mov ax,4c00h
            int 21h
cosesg  ends
end start
SI 和 DI

si 和 di 是 8086CPU中和 bx 功能相近的寄存器, si 和 di 不能分成两个8位寄存器
mov ax,[bx + si] -> (ax) = ((ds)*16 + (bx) + (si))

也可写成 mov ax,[bx][si]
mov ax,[bx + di] -> (ax) = ((ds)*16 + (bx) + (di))
也可写成 mov ax,[bx][di]

[bx+si+idata] 和 [bx+di+idata]

mov ax,[bx+si+idata] -> (ax) = ((ds)*16 + (bx) + (si) + idata)
该指令也可写成以下格式:

mov ax, [bx+200+si]
mov ax, [200+bx+si]
mov ax, 200[bx][si]
mov ax, [bx].200[si]
mov ax, [bx][si].200
不同的寻址方式的灵活应用

(1) [idata]用一个常量来表示地址, 可直接定位一个内存单元;
(2) [bx]用一个变量来表示内存地址, 可用于间接定位一个内存单元;
(3) [bx+idata]用一个变量和常量来表示地址, 可在一个起始地址的基础上用变量间接定位一个内存单元;
(4) [bx+si]用两个变量表示地址;
(5) [bx+si+idata]用两个变量和一个常量表示地址。

编程,将datasg 段中的每个单词改为大写字母。

assume  cs:codesg, ds:datasg
datasg  segment
    db  'ibm                '
    db  'dec                '
    db  'dos                '
    db  'vax                '
datasg  ends
codesg  segment
    mov ax, datasg
    mov ds, ax
    mov bx,0
    mov cx,4
s:  mov dx,cx               //将外层循环的cx值保存在 dx 中
    mov si,0
    mov cx,3                //cx 设置为内层循环的次数
s0: mov al, ds:[bx + si]
    and al,11011111B
    mov ds:[bx + si],al
    inc si
    loop s0

    add bx,16
    mov cx,dx               //用dx 中存放的外层循环的计数值恢复cx
    loop s                  //外层循环的 loop 指令将 cx 中的计数值减 1

    mov ax, 4c00h
    int 21h
codesg  ends
end start

不足:如果dx被占用,可用寄存器也有限,我们应考虑将暂存的数据放到内存单元中。
改进:

assume  cs:codesg, ds:datasg
datasg  segment
    db  'ibm                '
    db  'dec                '
    db  'dos                '
    db  'vax                '
    dw  0     // 定义一个字,用来暂存cx
datasg  ends
codesg  segment
    start:  mov ax, datasg
            mov ds, ax
            mov bx, 0
            mov cx, 4
        s:  mov ds:[40h],cx
            mov si,0
            mov cx, 3

        s0: mov al, ds:[bx+si]
            and al, 11011111B
            mov ds:[bx+si], al
            inc si
            loop s0

            add bx,16
            mov cx,ds:[40h]
            loop s

            mov ax, 4c00h
            int 21h
codesg  ends
end start

还可以改进:一般来说,在需要暂存数据的时候,我们都应该使用栈
大家可以自行尝试一下

第8章 <数据处理的两个基本问题>

定义描述性符号: reg 和 sreg
reg // 表示一个寄存器
sreg // 表示一个段寄存器

总结:

(1) 在8086CPU 中,只有这4个寄存器可以用在"[…]" 中来进行内存单元寻址
(2) 在[…]中,这4个寄存器可以单个出现,或只能以4中组合出现: bx 和 si、bx 和 di、bp 和 si、bp 和 di
(3) 只要在[…]中使用寄存器 bp,而指令中没有显示地给出段地址,段地址就默认在 ss 中

段地址(SA)和偏移地址(EA)

word ptr 和 byte ptr

mov     word    ptr     ds:[0],1        //指明指令访问的内存单元是一个字单元
mov     byte    ptr     ds:[0],1        //指明指令访问的内存单元是一个字节单元
div 指令

(1) 除数: 有8位和16位两种,在一个reg或内存单元中。
(2) 被除数: 默认放在 AX 或 DX 和 AX 中,如果除数为 8 位,被除数则为16位,默认放在AX中;
如果除数为16位,被除数则为 32 位,在 DX 和 AX 中存放,DX 存放高 16 位,AX 存放低 16 位。
(3) 结果: 如果除数为 8 位,则 AL 存储除法操作的商,AH 存储除法操作的余数;
如果除数为 16 位,则 AX 存储除法操作的商,DX 存储除法操作的余数。

编程,利用除法指令计算 100001/100

    mov dx,1
    mov ax,86A1
    mov bx,100
    div bx
伪指令 dd

回顾:

db用来定义字节型数据
dw用来定义字型数据
dd用来定义双字型数据

dup

dup 是一个操作符,在汇编语言中同 db、dw、dd 等一样,也是编译器识别处理的符号。用来进行数据的重复。
db 3 dup(0) // 定义了三个字节,它们的值都是0, 相当于db 0,0,0
db 3 dup(1,2,3) // 定义了9个字节,它们是0,1,2,0,1,2,0,1,2,相当于db 0,1,2,0,1,2,0,1,2

第 9 章 <转移指令的原理>

可以修改IP,或同时修改CS和IP的指令统称为转移指令。
分类

只修改 IP 时,称为段内转移,比如: jmp ax。
同时修改 CS 和 IP时,称为段间转移,比如: jmp 1000:0

段内转移又分为: 短转移和近转移

短转移IP的修改范围为-128~127
近转移IP的修改范围为-32768~32767
操作符offset

offset功能: 取得标号的偏移地址

assume  cs:codesg
codesg  segment
    start:mov   ax, offset start    //相当于mov ax,0
         :mov   ax, offset  s       //相当于mov ax,3
codesg  ends    
end     start
jmp 指令

jmp为无条件转移指令,可以只修改IP,也可以同时修改CS 和 IP
jmp指令要给出两种信息:
(1) 转移的目标地址
(2) 转移的距离(段间转移、段内短转移、段内近转移)

依据位移进行转移的 jmp 指令

jmp short 标号(转到标号处执行指令)
注意:这条指令对应的机器码中,并不包括转移的目的地址,而包含的是转移的位移。

jmp short   标号    //段内短转移
jmp near  ptr  标号 //段内近转移
jmp far   ptr  标号 //段间转移
jcxz 指令

jcxz 指令为有条件转移指令,所有的有条件转移指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址。对IP的修改范围都为-128~127。
指令格式: jcxz 标号(如果(cx)=0, 转移到标号处执行。)
相当于高级语言里的if条件判断

loop 指令

loop 指令为循环指令,所有的循环指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址。对 IP 的修改范围都为: -128~127
指令格式: loop 标号((cx)=(cx)-1, 如果(cx)!=0, 转移到标号处执行。)

第10章 <CALL 和 RET 指令>

ret 指令用栈中的数据,修改 IP 的内容,从而实现近转移
retf指令用栈中的数据,修改 CS 和 IP 的内容,从而实现远转移。

CPU执行 ret 指令时,进行下面两步操作(相当于pop IP):

(1) (IP) = ((ss)*16 + (sp))
(2) (sp) = (sp) + 2

CPU执行retf指令时,进行下面 4 步操作(相当于pop IP,pop CS):

(1) (IP) = ((ss)*16 + (sp))
(2) (sp) = (sp) + 2
(3) (CS) = ((ss)*16 + (sp))
(4) (sp) = (sp) + 2
call 指令

CPU执行call指令时,进行两步操作:

(1) 将当前的 IP 或 (CS 和 IP) 压入栈中;
(2) 转移

注意:call指令不能实现短转移,实现转移的方式和 jmp 指令的原理相同。

call 标号(将当前的IP压栈后,转到标号处执行指令)
CPU 执行此种格式的 call 指令时,进行如下的操作:

(1) (sp) = (sp) -2
    ((ss)*16 + (sp)) = (IP)
(2) (IP) = (IP) + 16位位移

CPU 执行 "call 标号"时,相当于进行:

push  IP
jmp  near ptr  标号

CPU 执行 “call far ptr 标号” 实现的是段间转移。

(1) (sp) = (sp) -2
    ((ss)*16 + (sp)) = (CS)
    (sp) = (sp) -2
    ((ss)*16 + (sp)) = (IP)
(2) (CS) = 标号所在段的段地址
    (IP) = 标号在段中的偏移地址
转移地址在寄存器中的 call 指令

指令格式: call 16位 reg
功能:

(sp) = (sp) -2
((ss)*16 + (sp)) = (IP)
(IP) = (16位reg)

相当于:

push  IP
jmp  16位 reg 
转移地址在内存中的 call 指令

(1) call word ptr 内存单元地址

push    IP
jmp   word   ptr  内存单元地址

(2) call dword ptr 内存单元地址

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

mul 是乘法指令,使用 mul 做乘法的时候,注意一下两点:

(1) 两个相乘的数:两个相乘的数,要么都是8位,要么都是 16 位。如果是 8 位,一个默认放在 AL 中,另一个放在 8 位 reg 或内存字节单元中;如果是 16 位,一个默认在 AX 中,另一个放在 16 位 reg 或内存字单元中。
(2) 结果: 如果是8位乘法,结果默认放在 AX 中; 如果是 16 位乘法,结果高位默认在 DX中存放,低位放在 AX 中 

格式如下:

mul     reg
mul     内存单元
编写子程序(综合ret 和 call)

(1) 编程计算data段中第一组数据的3次方,结果保存在后面一组dword单元中。

assume  cs:code
data    segment
    dw  1,2,3,4,5,6,7,8
    dd  0,0,0,0,0,0,0,0
data    ends

code    segment
    start:  mov ax,data
            mov ds,ax
            mov si,0    // ds:si 指向第一组word单元
            mov di,16   // ds:di 指向第二组dword单元

            mov cx,8
        s:  mov bx,[si]
            call cube
            mov [di],ax
            mov [di].2,dx
            add si,2    // ds:si 指向下一个 word 单元
            add di,4    // ds:di 指向下一个dword 单元
            loop s
            
            mov ax,4c00h
            int 21h
    cube:   mov ax,bx
            mul bx
            mul bx
            ret
code    ends
end     start

(2) 编程将data段中的字符串转化为大写

assume  cs:code 
data    segment
    db  'conversation'
data    ends

code    segment
    start:  mov ax,data
            mov ds,ax
            mov si,0
            mov cx,12
            call capital
            mov ax,4c00h
            int 21h
    capital:and byte ptr [si],11011111b
            inc si
            loop capital
            ret
code ends
end  start 
  • 68
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

linux-hzh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值