《汇编语言》第三版王爽 笔记汇总

前言

花了几天,回顾了一下这本书,也是做了份笔记。主控8086虽说有些老,但是感觉很适合汇编入门。时间充裕的建议去读一下原书,紧张的话,可以把博主的笔记过一遍。
电子版链接: 

链接:https://pan.baidu.com/s/1ID_QBuAyc2frZ59QJSoaqQ 
提取码:tbjq

基础知识

cpu 对存储器的读写

  • 存储单元的地址(地址信息)
  • 器件的选择,读或写的命令(控制信息)
  • 读或写的数据(数据信息)

总线

  • 地址总线的宽度决定了CPU的寻址能力
  • 数据总线的宽度决定了CPU与其他器件进行数据传输时的一次数据传输量
  • 控制总线的宽度决定了CPU对系统中其他器件的控制能力

pc系统中各类存储器的逻辑连接情况

内存地址空间

寄存器

通用寄存器

以8086 16位芯片为例,AX,BX,CX等都是16位通用寄存器, 为了兼容8位,衍生出了AL,AH,BL,BH,CL,CH等8位寄存器,分别代表低8位和高8位。

物理地址

结论

物理地址 = 段地址 << 4 + 偏移地址

背景

20位cpu,通过将两个16位寄存器送入到地址加法寄存器中,实现20位地址总线访问.

段寄存器

代码段寄存器和偏移寄存器

CS 是代码段寄存器, IP是指令指针寄存器

在8086CPU加电启动或复位后(即CPU刚开始工作时)CS和IP被设置为CS-FFFFH, IP=0000H,即在8086PC机刚启动时, CPU从内存FFFFOH单元中读取指令执行, FFFFOH单元中的指令是8086PC机开机后执行的第一条指令。

数据段寄存器和偏移寄存器

ds是段寄存器,偏移可以用常量或者变量等

栈段寄存器和偏移寄存器

SS是段寄存器,sp是偏移寄存器

修改段寄存器(实现代码运行跳转)

修改CS/IP
jmp 段地址(cs):偏移地址(ip)
jmp 2AE3:3  CS = 2AE3H  IP = 0003H 
cpu将从2AE33H处读取指令

ps: mov 指令只针对通用寄存器,并不是适用于CS/IP 段寄存器

修改IP
jmp 某合法寄存器
jmp ax   
执行前 ax = 1000H  CS = 2000H IP = 0003H
执行后 ax = 1000H  CS = 2000H IP = 1000H
jmp ax 类似等价于 mov IP,ax

代码段

示例代码
mov ax ,000
add ax ,0123H
mov bx ,ax
jmp bx
如何去执行示例代码?
  • 假设我需要把这段代码放到 123B0H ~ 123BH内存单元,将其定义为代码段。如果想要去执行,则把CS = 123BH,IP = 0000H即可
  • IP 每执行一条指令,会自动 + 该指令反汇编对应的字节数,实现自动跳转到下条指令

寄存器内存访问

DS 和 [address]

DS是访问数据的段地址寄存器,比如要读取 10000H地址的数据内容,代码如下

mov bx, 1000H
mov ds, bx
mov al, [0]
  • [...] 代表一个内存单元,[0] 就表示内存单元的偏移。
  • 所以mov al,[0] 为什么能取到10000H的数据,就是因为取数据的地址 = ds << 4 + 偏移
  • 也就是 1000H << 4 + 0 = 10000H

字的传送

实现一次性传送16位数据的code

mov bx, 1000H
mov ds, bx
mov ax, [0]
mov [0], cx

栈指令

  • push 段寄存器 将一个段寄存器中的数据入栈
  • pop 段寄存器 用一个段寄存器接收出栈的数据

源程序

assume cs:codesg
codesg segment
        mov ax, 0123H
        mov bx, 0456H
        add ax, bx
        add ax, ax

        mov ax, 4c00H
        int 21H
codesg ends
end
伪指令
XXX  segment
        ;
        ;
XXX  ends
  • 是一对成对使用的伪指令,用于定义一个段
  • segment是开始,ends是结束
end

程序结束的标志

assume

将特定用途的段和相关寄存器关联起来

标号

codesg 代表一个标号,一个标号代指一个地址. 这里最终会被编译,连接程序处理为一个段的段地址

程序返回
mov ax, 4c00H
int 21H

[BX] 和loop

[bx]

mov al, [0]  是把 ds<< + 0的内容赋值给al
mov al,[bx] 是把 ds<< + bx的内容赋值给al
( )
  • (ax)代表ax中的内容, (al)代表al中的内容
  • (2000H) 表示2000H这个地址的内容
  • (ds) 表示ds中的内容

()可以包含的类型有三种,分别是寄存器,物理地址,段寄存器

loop

cpu执行loop的时候,需要进行两步操作:

  1. (cx)=(cx) - 1
  2. 判断cs中的值,不为0则转到标号处执行程序,反之则向下执行
assume cs:codesg
codesg segment
        mov ax, 2
        mov cx, 11
     s: add ax, ax
        loop s
        mov ax, 4c00H
        int 21H
codesg ends
end
  • 实现效果: 2 累加11次,结果存放到ax中。

实验

效果:计算ffff:0 ~ ffff:b内存单元中的数据和,结果存放到dx中。

assume cs:codesg
codesg segment
        mov ax, 0ffffH
        mov ds, ax
        mov bx, 0
        mov dx, 0
        mov cx, 12
     s: mov al, [bx]
        mov ah, 0
        add dx, ax
        inc bx
        loop s
        mov ax, 4c00H
        int 21H
codesg ends
end

包含多个段的程序

代码段中使用数据

assume cs:codesg
codesg segment
    dw 0x123H, 0456H, 0789H, 0abcH
    start   mov bx, 0
            mov ax, 0
    
            mov cx, 8
         s: add ax, cs:[bx]
            add bx, 2
            loop s
        
            mov ax, 4c00H
            int 21H
codesg ends
end start

实现效果,把dw 数据累加

代码段中使用栈

assume cs:codesg
codesg segment
    dw 0123H, 0456H, 0789H, 0abcH, 0defH
    dw 0000H, 0000H, 0000H, 0000H, 0000H
    start   mov ax, cs
            mov ss, ax
            mov sp, 30H

            mov bx, 0
            mov cx, 8
         s: push cs:[bx]
            add bx, 2
            loop s  //将0~15地址的内容依次入栈

            mov bx, 0
            mov cx, 8
        s0: pop cs:[bx]
            add bx, 2
            loop s0 //将0~15地址的内容依次出栈
        
            mov ax, 4c00H
            int 21H
codesg ends
end start

将数据,代码,栈放入不同的段

assume cs:codesg
    data segment
        db 0123H, 0456H, 0789H, 0abcH, 0defH
    data ends 

    stack segment
        dw 0000H, 0000H, 0000H, 0000H, 0000H
    stack ends

    code segment
        start   mov ax, stack
                mov ss, ax
                mov sp, 20H

                mov ax, data
                mov ds, ax
                
                mov bx, 0
                mov cx, 8
             s: push cs:[bx]
                add bx, 2
                loop s  //将0~15地址的内容依次入栈
    
                mov bx, 0
                mov cx, 8
            s0: pop cs:[bx]
                add bx, 2
                loop s0 //将0~15地址的内容依次出栈
            
                mov ax, 4c00H
                int 21H
     code ends
end start

更灵活的定位内存地址

或与运算

  • add 进行与运算
  • or 进行或运算

以字符的形式给出的数据

assume cs:codesg
    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

大小写转换

assume cs:codesg, ds:data
    data segment
        db 'BaSiC'
        db 'iNfOr'
    data ends 

    code segment
        start   mov ax, data
                mov ds, ax
                
                mov bx, 0
                mov cx, 5
             s: mov al, [bx]
                and al, 11011111B
                mov [bx], al
                inc bx
                loop s  
    
                mov bx, 5
                mov cx, 11
            s0: mov al, [bx]
                or al, 00100000B
                mov [bx], al
                inc bx
                loop s0  
                mov ax, 4c00H
                int 21H
     code ends
end start

大小写转换优化([bx + idata])

assume cs:codesg, ds:data
    data segment
        db 'BaSiC'
        db 'iNfOr'
    data ends 

    code segment
        start   mov ax, data
                mov ds, ax
                
                mov bx, 0
                mov cx, 5
             s: mov al, [bx]  // or mov al, 0[bx]
                and al, 11011111B
                mov [bx], al
                mov al, [bx + 5] // or mov al, 5[bx]
                or al, 00100000B
                mov [bx + 5], al
                inc bx
                loop s
                mov ax, 4c00H
                int 21H
     code ends
end start

大小写转换(c语言版 )

char a[5] = "BaSiC";
char b[5] = "MinIX"
main()
{
    int i = 0;
    do {
        a[i] &= 0xdf;
        b[i] |= 0x20;
        i++;
    } while(i < 5);
}

SI和DI

si和di是鱼bx功能相近的寄存器,不过不能分成两个8位寄存器来使用。

小练-> 使用si和di 将某个字符串复制到它后面的数据区
assume cs:codesg, ds:data
    data segment
        db 'welcome to masm!' //一共16个字符
    data ends 

    code segment
        start   mov ax, data
                mov ds, ax
                mov si, 0
                mov di, 16
                mov cx, 8
             s: mov ax, [si]  
                mov [di], ax
                mov al, [bx + 5] 
                add si, 2
                add di, 2 //16位寄存器一次性复制两个字节
                inc bx
                loop s
                mov ax, 4c00H
                int 21H
     code ends
end start

不同的寻址方式的灵活应用

  • [idata] 用一个常量来表示地址,可用于直接定位一个内存单元。
  • [bx] 用一个变量来表示内存地址,可用于间接定位一个内存单元
  • [bx+idata]用一个变量和常量来表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元
  • [bx+si]用两个变量表示地址
  • [bx+si+idata]用于两个变量和一个常量来表示地址
小练1-> 将data段每一个单词的头一个字母改成大写
assume cs:codesg, ds:data
    data segment
        db '1.file    '
        db '2.edit     ' 
        db '3.search     '
        db '4.view  '
        db '5.options  '
        db '6.help    '
    data ends 

    code segment
        start   mov ax, data
                mov ds, ax
                
                mov bx, 0
                mov cx, 6
             s: mov al, [bx + 3]  
                and al, 11011111B
                mov [bx + 3], al
                add bx, 16
                loop s
                mov ax, 4c00H
                int 21H
     code ends
end start
小练2-> 把data段中每一个单词都改成大写
assume cs:codesg, ds:data
    data segment
        db 'ibm    '
        db 'dec    ' 
        db 'dos    '
        db 'vax    '
    data ends 

    code segment
        start   mov ax, data
                mov ds, ax         
                mov bx, 0
                mov cx, 4
             s0:mov si, 0
                mov cx, 3
             s: mov al, [bx + si]  
                and al, 11011111B
                mov [bx + si], al
                inc si
                loop s
                add bx, 16
                loop s0
                mov ax, 4c00H
                int 21H
     code ends
end start
assume cs:codesg, ds:data
    data segment
        db 'ibm    '
        db 'dec    ' 
        db 'dos    '
        db 'vax    '
    data ends 

    code segment
        start   mov ax, data
                mov ds, ax         
                mov bx, 0
                mov cx, 4
             s0:mov dx, cx
                mov si, 0
                mov cx, 3
             s: mov al, [bx + si]  
                and al, 11011111B
                mov [bx + si], al
                inc si
                loop s
                add bx, 16
                mov cx, dx
                loop s0
                mov ax, 4c00H
                int 21H
     code ends
end start
assume cs:codesg, ds:data
    data segment
        db 'ibm    '
        db 'dec    ' 
        db 'dos    '
        db 'vax    '
        db 0
    data ends 

    code segment
        start   mov ax, data
                mov ds, ax         
                mov bx, 0
                mov cx, 4
             s0:mov ds:[1cH], cx
                mov si, 0
                mov cx, 3
             s: mov al, [bx + si]  
                and al, 11011111B
                mov [bx + si], al
                inc si
                loop s
                add bx, 16
                mov cx, ds:[1cH]
                loop s0
                mov ax, 4c00H
                int 21H
     code ends
end start
assume cs:codesg, ds:data
    data segment
        db 'ibm    '
        db 'dec    ' 
        db 'dos    '
        db 'vax    '
    data ends 

    stack segment
        dw 0, 0, 0, 0, 0, 0, 0, 0,
    stack ends
    code segment
        start   mov ax, data
                mov ds, ax  
                mov ax, stack
                mov ss, ax
                
                mov bx, 0
                mov cx, 4
             s0:push, cx
                mov si, 0
                mov cx, 3
             s: mov al, [bx + si]  
                and al, 11011111B
                mov [bx + si], al
                inc si
                loop s
                add bx, 16
                pop cx
                loop s0
                mov ax, 4c00H
                int 21H
     code ends
end start

数据处理

寻址方式小结

div指令

div 是除法指令,使用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存储除法操作的余数。
小练1 100001/100
mov dx, 1
mov ax, 86a1H
mov bx, 100
mov bx
结果存放在ax = 03E8H dx(余数) = 1
小练2 1001/100
mov ax, 1001
mov bl, 100
div bl
结果存放在 al = 0AH ah(余数) = 1

伪指令dd

dd是用于定义dword型数据的。

data segment
    db 1
    dw 1
    dd 1
data ends
  • 第一个数据为01H,在data:0处,占一个字节。
  • 第二个数据为0001H,在data:1处,占一个字节。
  • 第三个数据为00000001H,在data:3处,占两个字节

dup

配合db, dw, dd等数据定义伪指令配合使用的,用于进行数据的重复。

db 3 dup(0)   -> //定义了三个字节,他们的值都是0,相当于db 0, 0, 0
db 3 dup(0, 1, 2) -> //定义了九个字节,分别是0, 1, 2, 0, 1, 2, 0, 1, 2,
db 3 dup('abc', 'ABC') ->//定义了18个字节,'abcABCabcABCabcABC'

转移指令的原理

概括的讲,转移指令就是可以控制CPU执行内存中某处代码的指令

8086cpu的转移行为有:

  1. 只修改IP时,成为段内转移,比如jmp ax
  2. 同时修改IP和CS时,成为段间转移,比如jmp 1000:0

根据对IP的修改范围不同,段内转移又分为:

  1. 短转移
  2. 长转移

转移指令分为:

  1. 无条件转移指令
  2. 条件转移指令
  3. 循环指令
  4. 过程
  5. 中断

操作符offset

功能是取得标号的偏移地址

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

jmp short

段内短转移,对ip的修改范围是-128~127.

jmp far ptr

段间转移

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

转移地址在内存中的imp指令

  • jmp word ptr 内存单元地址(段内)
mov ax, 0123H
mov ds:[0], ax
jmp word ptr ds:[0]
//执行结束 IP = 0123H
  • jmp dword ptr 内存单元地址(段间)
  • 高地址的字是转移的目的段地址,低地址处是转移的目的偏移地址
  • CS = 内存单元地址+2
  • IP = 内存单元地址
mov ax, 0123H
mov ds:[0], ax
mov word ptr ds:[2], 0
jmp dword ptr ds:[0]
//执行结束 CS = 0 IP = 0123H

jcxz指令

有条件转移指令 等价于 if(cx == 0) jmp short xxx

CALL和RET

ret和retf

  • ret从栈中取缓存的ip数据,覆盖IP,实现近转移
  • retf从栈中取缓存的cs和ip数据,覆盖cs和ip,实现远转移

mul指令

乘法指令,使用时需要注意:

  1. 两个相乘数:要么都是8位,要么都是16位。如果是8位,一个默认放在AL中,另一个放在8位reg或者内存字节单元中。 如果是16位,一个默认在AX中,另一个放在16位reg或者内存字节单元中。
  2. 结果:如果是8位乘法,结果默认放在AX中。如果是16位乘法,结果高位默认放在DX中,低位默认放在AX中。
小练1
mov al, 100
mov bl, 10
mul bl
结果 ax = 1000
小练2
mov ax, 100
mov bx, 10000
mul bx
结果: ax = 4240H dx = 000FH

参数和结果传递

小练1
/*计算N的3次方子程序
 * 参数 bx = N
 * 结果 dx:ax = N^3
 */
cube: mov ax, bx
      mul bx
      mul bx
      ret
小练2
assume cs:code
 data segment
     dw 1, 2, 3, 4, 5, 
     dd 0, 0, 0, 0, 0,
 data ends
code segment
    start: mov ax, data
           mov ds, ax
           mov si, 0
           mov di 16

           mov cx, 8
        s: mov bx, [si]
           call cube
           mov [di], ax
           mov [di].2, dx
           add si, 2
           add di, 4
           loop s

           mov ax, 4a00h
           int 21h
           
        cube: mov ax, bx
              mul bx
              mul bx
              ret
code ends
end start
小练3
assume cs:code
 data segment
     db 'sdagfdggethj'
 data ends
code segment
    start: mov ax, data
           mov ds, ax
           mov si, 0
           mov cx, 12
           call capital
           mov ax, 4a00h
           int 21h
           
  capital: and byte ptr [si], 11011111b
           inc si
           loop capital
           ret
code ends
end start

标志寄存器

这类寄存器的作用:

  1. 存储相关指令的某些执行结果
  2. 为CPU执行相关指令提供行为依据
  3. 控制CPU的相关工作方式

影响标志寄存器的指令执行,大多数逻辑运算或者算数运算,ps: add, sub, mul, dul, inc, or, and. 不影响标志寄存器的指令有mov, push,pop等,大多数传送指令。

ZF标志

记录相关指令执行后,其结果是否为0。如果为0,zf=1,反之,zf=0

PF标志

奇偶校验位,记录相关指令执行后,其结果的所有bit位中的1的个数是否为偶数。 如果1的个数为偶数,pf = 1, 反之,pf = 0

SF标志

符号标志位,记录了相关指令执行后,其结果是否为负数。如果为负,sf = 1, 反之 sf = 0

CF标志

进位标志位,在进行无符号运算时,记录了运算结果的最高有效位向更高位的进位值,或者更高位的借位值。

OF标志

溢出标志位,记录了有符号数运算的结果是否发生溢出,如果发生溢出,of = 1, 反之,of = 0

adc指令

带进位加法指令

  • 指令格式:adb 操作对象1,操作对象2
  • 功能:对象1 = 对象1 +对象2 + CF
  • 指令 adc ax, bx 实现了ax = ax + bx + cf
为什么要加cf?

进行加法的第二步运算,add和adc配合起来可以对更大的数据,进行加法运算。

//结果 最高16位放在ax, 次高16位放在bx, 低16位放在cx中
//1. 先将低16位相加,CF记录本次相加的进位值
//2. 再把次高16位和CF相加,CF记录本次相加的进位值
//3. 最后高16位和CF相加,CF记录本次相加的进位值
mov ax, 001EH
mov bx, 0F000H
mov cx, 1000H
add cx, 1EF0H
adc bx, 1000H
adc ax, 0020H

sbb指令

带借位减法指令

cmp指令

比较指令,相当于减法指令,不过不保存结果。执行后,对标志状态寄存器产生影响。

// cmp ax, ax 结果为0,不保存,flag状态位 zf=1 pf=1 sf=0 cf=0 of=0

mov ax, 8
mov bx, 3
cmp ax, bx
//执行后 ax=8 zf=0 pf=1 sf=0 cf=0 of=0

检测比较结果的条件转移指令

DF标志和串传送指令

DF是方向标志位,在串处理指令中,控制每次操作后si, di的增减。

  • df=0 每次操作后,si, di递减
  • df=1 每次操作后,si, di递增
movsb

功能就是把ds:si的内存单元中的byte送到es:di中,然后根据df的值,判断递增还是递减

  1. es*16 +di = ds * 16 + si
  2. if df == 0 则si = si + 1, di = di + 1
  3. if df == 1 则si = si - 1, di = di -1
movsw

功能就是把ds:si的内存单元中的word送到es:di中,然后根据df的值,判断递增还是递减

使用

配合rep来使用movsb or movsw

rep movsb 等价于
s: movsb
 loop s
小练
data segment
    db 'welcome to main!'
    db 16 dup(0)
data ends
mov ax, data
mov ds, ax
mov si, 0
mov es, ax
mov di, 16
mov cx, 16
cld
rep movsb

pushf和popf

pushf 是将标志寄存器的值压栈,popf是从栈中弹出数据,送到标志寄存器。

内中断

产生

当cpu内部有下面的情况发生的时候,将产生相应的中断信息:

  1. 除法错误 ps: 执行div指令产生的除法溢出
  2. 单步执行
  3. 执行into指令
  4. 执行int指令

中断类型码:

  1. 除法错误:0
  2. 单步执行:1
  3. 执行into指令:4
  4. 执行int指令:int n, n为字节型立即数,提供给cpu的中断类型码

设置中断向量

将do0的入口地址0:200,写入中断向量表的0号表项中,使do0成为0号中断的中断处理程序

0号表项的地址为0:0, 其中0:0字单元存放偏移地址,0:2字单元存放段地址。

mov ax, 0
mov es, ax
mov word ptr es:[0*4], 200h
mov word ptr esL[0*4 + 2], 0

int指令

格式为 int n, n为中断类型码,功能是引发中断过程。

小练

assume cs:code
code segment
    start: mov ax, cs
           mov ds, ax
           mov si, offset spr
           mov ax, 0
           mov es, ax
           mov di, 200h
           mov cx, offset sprend-offset spr
           cld
           rep movsb

           mov ax, 0
           mov es, ax
           mov word ptr es:[7ch*4], 200h
           mov word ptr es:[7ch*4], 0

           mov ax, 4a00h
           int 21h

    spr: mul ax
        iret
    sqrend:nop
code ends
end start
           

端口

shl指令

逻辑左移指令,功能:

  1. 将寄存器或者内存单元中的数据向左移位。
  2. 将最后移出的一位写入到CF中
  3. 最低位用0补充
mov al, 01001000b
shl al, 1
// 执行后,al = 10010000b cs = 0

shr指令

逻辑右移指令,功能:

  1. 将寄存器或者内存单元中的数据向右移位
  2. 将最后移出的一位写入到CF中
  3. 最高位用0补充
mov al, 10000001b
shr al, 1
// 执行后,al = 01000000b cf = 1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值