《汇编语言》王爽著学习笔记记录(后半部分)

第七章:更灵活的定位内存地址的方法

  1. and 和 or 指令:

    指令 功能
    and 将操作对象的相应位设为0,其它位不变 将al的第0位设为0:and al,11111110B
    or 逻辑或指令,按位进行或运算 将al的第6位设为1:or al,01000000B

    使用这两个命令可以帮助我们对内存中的数据按位置 0 或 1.

  2. 指明内存单元的另一个方法:[bx + idata]来访问一个内存单元(一个变量一个常量),其代表的是一个偏移地址;这种内存访问方式为高级语言实现数组提供了便利机制。

    命令 mov ax,[200 + bx] 的含义为: (ax) = ((ds) * 16 + (bx) + 200)

    通用写法:

    1. mov ax,[bx + 200]
    2. mov ax,200[bx]
    3. mov ax,[bx].200
  3. si 和 di 是8086CPU中两个和 bx 功能相近的寄存器, 但不能分为两个 8 为寄存器来使用。

    1. mov bx,0
      mov ax,[bx]
      mov si,0
      mov ax,[si]
      mov di,0
      mov ax,[di]
      mov bx,0
      
      mov ax,[bx + 123]
      mov si,0
      mov ax,[si + 123]
      mov di,0
      mov ax,[di + 123]

上面的代码说明了si 与 di 同 bx 使用上的相同之处。

  1. 我们可以使用 [bx (si 或 di)](一个变量) 、[bx (si 或 di) + idata] (一个变量和一个常量)来指明一个内存单元,还有 [bx + si] 、[bx + di] (两个变量)

    mov ax,[bx + si] ;(ax) = ((ds) * 16 + (bx) + (si))

    常用形式: mov ax,[bx] [si]

  2. 更多的内存访问方式:[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
  3. 将datasg中的每个单词改为大写字母:

     ;版本1
     ;使用 dx 寄存器临时保存 cx 中的值
    assume cs:codesg,ds:datasg
    
    datasg segment
         db 'ibm             '
        db 'dec             '
        db 'dos             '
        db 'vax             '
    datasg ends
    
    codesg segment
    start: mov ax,datasg
           mov ds,ax
           mov bx,0                  ;此时指向第一行第一个字节的字母
    
           mov cx,4
    
       s0: mov dx,cx                 ;将 cx 的值暂存到 dx 中
              mov si,0
              mov cx,3
    
        s: mov al,[bx + si]          ;(al) = ((ds) * 16 + (bx) + (si))
           and al,11011111b          ;将小写字母改为大写字母
           mov [bx + si],al          ;((ds) * 16 +(bx) + (si)) = (al)
           inc si                    ;si + 1
    
           loop s
    
           add bx,16                 ;00 → 10 → 20 → 30 ...
           mov cx,dx                 ;将暂存的 cx 返回
           loop s0                   ;cx - 1
    
    codesg ends
    end start
     ;版本2
     ;使用栈空间来暂存数据,前面我们使用的是寄存器,但有些时候寄存器是不足的,不是可取的办法
    assume cs:codesg,ds:datasg,ss:stacksg
    
    datasg segment
         db 'ibm             '
        db 'dec             '
        db 'dos             '
        db 'vax             '
    datasg ends
    
    stacksg segnebt
            dw 0,0,0,0,0,0,0,0,0   ;定义一个段用作栈段,容量为16字节
    stacksg ends
    
    codesg segment
    start: mov ax,stacksg
           mov ss,ax
           mov sp,16
           mov ax,datasg
           mov ds,ax
           mov bx,0                  ;此时指向第一行第一个字节的字母
    
           mov cx,4
    
       s0: push cx                   ;将外循环 cx 的值压栈
              mov si,0
              mov cx,3                  ;内循环 cx 的值
    
        s: mov al,[bx + si]          ;(al) = ((ds) * 16 + (bx) + (si))
           and al,11011111b          ;将小写字母改为大写字母
           mov [bx + si],al          ;((ds) * 16 +(bx) + (si)) = (al)
           inc si                    ;si + 1
    
           loop s
    
           add bx,16                 ;00 → 10 → 20 → 30 ...
           pop cx                    ;将暂存的 cx 返回
           loop s0                   ;cx - 1
    
           mov ax,4c00H
           int 21H
    
    codesg ends
    end start

    在需要暂存数据的时候,一般使用栈来操作

  4. 将 datasg 段中每个单词前4个字母改为大写:

    assume cs:codesg,ds:datasg,ss:stacksg
    
    datasg segment
         db '1. display      '
        db '2. brows        '
        db '3. replace      '
        db '4. modify       '
    datasg ends
    
    stacksg segnebt
            dw 0,0,0,0,0,0,0,0,0   ;定义一个段用作栈段,容量为16字节
    stacksg ends
    
    codesg segment
    start: mov ax,stacksg
           mov ss,ax
           mov sp,16
           mov ax,datasg
           mov ds,ax
           mov bx,0                  ;此时指向第一行第一个字节的字母
    
           mov cx,4
    
       s0: push cx                   ;将外循环 cx 的值压栈
              mov si,0
              mov cx,4                  ;内循环 cx 的值
    
        s: mov al,[bx + 3 + si]      ;(al) = ((ds) * 16 + (bx) + (si) + 3)
           and al,11011111b          ;将小写字母改为大写字母
           mov [bx + 3 + si],al      ;((ds) * 16 +(bx) + (si) + 3) = (al)
           inc si                    ;si + 1
    
           loop s
    
           add bx,16                 ;00 → 10 → 20 → 30 ...
           pop cx                    ;将暂存的 cx 返回
           loop s0                   ;cx - 1
    
           mov ax,4c00H
           int 21H
    
    codesg ends
    end start

第八章:数据处理的两个基本问题

  1. 描述性符号:

    符号 功能 集合
    reg 代表一个寄存器 ax、bx、cx、dx、ah、al、bh、bl、ch、cl、dh、dl、sp、bp、si、di
    sreg 代表一个段寄存器 ds、ss、cs、es
  2. 在8086CPU中,只有bx 、si、di、bp四个寄存器可以用在 […] 中来进行内存单元的寻址。

    在 […] 中,这四个寄存器可以单个出现,或者以4种组合出现:bx和si、bx和di、bp和si、bp和di

    mov ax,[bx]
    mov ax,[si]
    mov ax,[di]
    mov ax,[bp]
    mov ax,[bx + si]
    mov ax,[bx + di]
    mov ax,[bp + si]
    mov ax,[bp + di]
    mov ax,[bx + si + idata]
    mov ax,[bx + di + idata]
    mov ax,[bp + si + idata]
    mov ax,[bp + di + idata]
  3. 使用寄存器 bp 进行寻址,如果没有显性的给出段地址,那么段地址默认在 ss 段寄存器中

    mov ax,[bp] ;(ax) = ((ss) * 16 + (bp))
    mov ax,[bp + si + idata] ;(ax) = ((ss) * 16 + (bp) + (si) + idata)
  4. 处理指令大致分为3类:读取、写入、运算;指令执行前,数据一般在3个地方:CPU内部、内存、端口

  5. 数据的位置:

    1. 立即数(idata):在汇编指令中字节给出

      mov ax,1
      add bx,2000H
    2. 寄存器:要处理的数据在寄存器中,在汇编指令中给出相应的寄存器名就可以。

    3. 段地址(SA)和偏移地址(EA):指令要处理的数据在内存中,使用段地址+偏移地址定位内存单元。

  6. 寻址方式总结:

    寻址方式 含义 名称 常用格式
    [idata] EA = idata;SA = (ds) 直接寻址 [idata]
    [bx] EA = (bx);SA = (ds) 寄存器间接寻址 [bx]
    [si] EA = (si) ;SA = (ds)
    [di] EA = (di);SA = (ds)
    [bp] EA = (bp);SA = (ds)
    [bx + idata] EA = (bx) + idata;SA = (ds) 寄存器相对寻址 用于结构体:[bx].idata
    [si + idata] EA = (si) + idata;SA = (ds) 用于数组:idata[si],idata[di]
    [di + idata] EA = (di) + idata;SA = (ds) 用于二维数组:[bx] [idata]
    [bp + idata] EA = (bp) + idata;SA = (ss)
    [bx + si] EA = (bx) + (si);SA = (ds) 基址变址寻址 用于二维数组:[bx] [si]
    [bx + di] EA = (bx) + (di);SA = (ds)
    [bp + si] EA = (bp) + (si);SA = (ss)
    [bp + di] EA = (bp) + (di);SA = (ss)
    [bx + si + idata] EA = (bx) + (si) + idata;SA = (ds) 相对基址变址寻址 用于表格中的数组:[bx].idata[si]
    [bx + di + idata] EA = (bx) + (di) + idata;SA = (ds)
    [bp + si + idata] EA = (bp) + (si) + idata;SA = (ss) 用于二维数组:idata[bx] [si]
    [bp + di + idata] EA = (bp) + (di) + idata;SA = (ss)
  7. 8086CPU 可以处理 byte 和 word 两种尺寸的数据。

    1. 通过寄存器名指明要处理的数据的尺寸:

      ;字操作
      mov ax,1
      add ax,1000
      inc ax
      ;字节操作
      mov al
      add al000
      inc al
  1. 没有寄存器名存在得情况下,用操作符 X ptr 指明内存单元的长度,X 可以为 byte 或 word:

    ;word ptr 表示访问一个字单元
    mov word ptr ds:[0],1
    inc word ptr [bx]
    inc word ptr ds:[0]
    add word ptr [bx],2
    ;byte ptr 表示访问一个字节单元
    mov byte ptr ds:[0],1
    inc byte ptr [bx]
    inc byte ptr ds:[0]
    add byte ptr [bx],2

在机器指令中指明要访问的是字单元还是字节单元是非常重要的,8086CPU中,一个byte为8bit,而一个字为2byte,如果不指明,那么在访问的时候是有区别的。

  1. 使用 push 和 pop 指令就代表了是进行字操作,无需指明

  2. div 除法指令:

    (1)除数:8位和16位两种,在一个reg或内存单元中

    (2)被除数:默认在AX或AX和DX中,除数位8位,被除数位16位,默认在AX中存放;除数位16位,则被除数位32位,DX存放高16位,AX存放低16位。

    (3)结果:如果除数位8位,则AL存储除法操作的商,AH存放余数;如果除数位16位,AX存储除法操作的商,DX存放余数

    ;格式
    div reg
    div 内存单元
    ;示例
    div byte ptr ds:[0]      ;(al) = (ax) / ((ds) * 16 + 0 )的商
                           ;(ah) = (ax) / ((ds) * 16 + 0)的余数
    
    div word ptr es:[0]      ;(ax) = [(dx) * 10000H + (ax) / (es) * 16 + 0]的商
                           ;(dx) = [(dx) * 10000H + (ax) / (es) * 16 + 0]的余数
    
    div byte ptr [bx + si + 8]     ;(al) = (ax) / ((ds) * 16 + (bx) + (si) + 8)的商
                                 ;(ah) = (ax) / ((ds) * 16 + (bx) + (si) + 8)的余数
    
    div word ptr [bx + si + 8]     ;(ax) = [(dx) * 10000H + (ax) / (ds) * 16 + (si) + 8]的商
                                 ;(dx) = [(dx) * 10000H + (ax) / (ds) * 16 + (si) + 8]的余数js
  3. 计算:100001 / 100

    ;100001 > 65535,所以除数得是32位,转为16进制为 186A1H,所以高16位在DX中,低16位在AX中
    mov dx,1
    mov ax,86A1H
    mov bx,100
    div bx
  1. 伪指令 dd 、dup

    指令 功能 示例
    db 定义字节型数据 db 1
    dw 定义字型数据 dw 100
    dd 定义dword双字型数据 dd 100001
    dup 与上面3个指令配合使用,用来进行数据的重复 db(dw、dd) 重复次数 dup (重复的数据)
  1. 汇编语言实验七:

    ;题目太长,只贴代码,先思考写代码,而后体会别人的代码
    assume cs:code
    
    data segment
     db '1975','1976','1977','1978','1979','1980','1981','1982','1983','1984','1985'
     db '1986','1987','1988','1989','1990','1991','1992','1993','1994','1995'
    
     dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514,345980
     dd 590827,803530,1183000,1843000,2758000,3753000,4649000,5937000
    
     dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
     dw 11542,14430,15257,17800
    data ends
    
    stack segment
     dw 0,0,0,0,0,0,0
    stack ends
    
    table segment
     db 21 dup ('year summ ne ?? ')
    table ends
    
    code segment
    
    start:
        mov ax,data
        mov es,ax
        mov si,0
    
        mov ax,table
        mov ds,ax
        mov di,0
    
        mov ax,stack
        mov ss,ax
        mov sp,16
    
        mov bx,0
        mov cx,21
    s0:
        mov ax,es:[si]    
        mov ds:[di+bx],ax
        add si,2
        add di,2
        mov ax,es:[si]
        mov ds:[di+bx],ax
    
        mov ax,es:[si+82]
        mov ds:[bx+di+3],ax
        mov ax,es:[si+84]
        mov ds:[bx+di+5],ax
    
        add si,2
        mov di,0
        add bx,16
        loop s0
    
        mov bx,0
        mov si,168
        mov di,5
        mov cx,21
    s1:    
        mov ax,es:[si]
        mov ds:[bx+di+5],ax
    
        mov ax,ds:[bx+di]
        mov dx,ds:[bx+di+2]
        div word ptr ds:[bx+di+5]
        mov ds:[bx+di+8],ax
    
        add si,2
        add bx,16
        loop s1
    
        mov ax,4c00h
        int 21h
    
    code ends
    end start

第九章:转移指令的原理

  1. 可以修改 IP ,或者同时修改 CS 和 IP 得指令统称为转移指令。

    1. 段内转移:jmp ax
      1. 短转移IP修改范围:-128~127
      2. 近转移IP修改范围:-32768~32767
    2. 段间转移:jmp 1000:0
  2. 转移指令分为无条件转移指令(jmp)和条件转移指令、循环指令、过程、中断等等

  3. 操作符 offset ,能够取得标号的偏移地址:

    start: mov ax,offset start  ;取得start的偏移地址,相当于 mov ax,0

第十章:CALL和RET指令

  1. 第十一章:标志寄存器

第十二章:内中断

  1. 第十三章:int 指令

第十四章:端口

  1. 第十五章:外中断

第十六章:直接定址表

  1. 第十七章:使用BIOS进行键盘输入


   转载规则


《《汇编语言》王爽著学习笔记记录(后半部分)》 Tyzhao 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录