汇编语言笔记(一):基础

章节目录

  1. 简单程序
  2. 使用段
  3. 简单字符串处理程序
  4. 使用 bx, si, di, bp 寄存器寻址
  5. 寻址方法
  6. 指明数据长度
  7. div指令

作者能力有限, 如果您在阅读过程中发现任何错误, 还请您务必联系本人,指出错误, 避免后来读者再学习错误的知识.谢谢!

本文中所有程序均在DOSBox下使用MASM, LINK编译运行

简单程序

汇编语言笔记(一):基础

  • segment…ends: 伪指令, 用来定义一个段(比如,代码段,数据段,堆栈段), segment 标识一个段的开始, ends 标识一个段的结束.
  • 语法:
    SegmentName segment
    ..
    SegmentName ends

  • assume: 伪指令, 它假设某一段寄存器和程序中的某一个用 segment..ends 定义的段相关联.


  • mov ax, 4c00h
    int 21h

    称为程序返回,它的作用是将 CPU 的控制权交还给使他得以运行的程序.
  • 使用段

    汇编语言笔记(一):基础

    使用 assume 将我们定义的数据段,堆栈段,代码段和对应的段寄存器关联起来.

    cs 寄存器对应代码段
    ds 寄存器对应数据段
    ss 寄存器对应堆栈段

    值得注意, 我们在访问数据段或者堆栈段的时候,总是将段基址先保存在 ax 中,然后由 ax 保存到 ds 或者 ss. 为什么不直接将段基址保存到 ds 或者 ss 中? 答案是该操作非法.

    简单字符串处理程序

    汇编语言笔记(一):基础

    在这里, 我们使用 bx + offset 的语法访问数据段中的字符串. 相应的字符的地址计算方法为 addr=ds16+bx+offset.

    这里 offset 一般为常量. 如果不是常量, 我们可以使用 [bx+di+offset] 来完成. 相应的字符的地址计算方法为 addr=ds16+bx+di+offset.
    对于栈的访问可以使用 [bx+si+offset] 的方式访问. 相应的字符的地址计算方法为 addr=ds16+bx+si+offset.

    使用 bx, si, di, bp 寄存器寻址

  • 只有这四个寄存器可以用在 ‘[…]’ 中来进行内存单元寻址
  • 比如:
    mov ax, [bx]
    mov ax, [bx+si]
    mov ax, [bx+di]
    可以使用 bp 替换 bx.

    //以下用法是错误的
    mov ax, [ax]
    mov ax, [cx]
    mov ax, [dx]
    mov ax, [ds]

  • 这四个寄存次可以单个出现在 ‘[…]’ 中或者以组合出现.
  • 组合形式只能是以下四种:

    mov ax, [bx + si + offset]
    mov ax, [bx + di + offset]
    mov ax, [bp + si + offset]
    mov ax, [bp + si + offset]
    当然 offset 可以为零.

    //以下用法是错误的
    move ax, [di + si]
    move ax, [bx + bp]

  • 只要在 ‘[…]’ 中使用 bp 寄存器, 而指令中没有显式的给出段地址, 段地址默认在 ss 中.
  • 寻址方法

  • 直接寻址
  • 如: mov ax, [0] // 段基址在 ds 中

  • 寄存器间接寻址
  • 如:
    mov ax, [bx] // 段基址在 ds 中. bx 指明偏移
    mov ax, [si] // 段基址在 ds 中. si 指明偏移
    mov ax, [di] // 段基址在 ds 中. di 指明偏移
    mov ax, [bp] // 段基址在 ss 中. bp 指明偏移

  • 寄存器相对寻址
  • 如:
    mov ax, [bx+offset] // 段基址在 ds 中. bx+offset 指明偏移
    mov ax, [si+offset] // 段基址在 ds 中. si+offset 指明偏移
    mov ax, [di+offset] // 段基址在 ds 中. di+offset 指明偏移
    mov ax, [bp+offset] // 段基址在 ss 中. bp+offset 指明偏移

  • 基址变址寻址
  • 如:
    mov ax, [bx+si] // 段基址在 ds 中. bx+si 指明偏移
    mov ax, [bx+di] // 段基址在 ds 中. bx+di 指明偏移
    mov ax, [bp+si] // 段基址在 ss 中. bp+si 指明偏移
    mov ax, [bp+di] // 段基址在 ss 中. bp+di 指明偏移

  • 相对基址变址寻址
  • 如:
    mov ax, [bx+si+offset] // 段基址在 ds 中. bx+si+offset 指明偏移
    mov ax, [bx+di+offset] // 段基址在 ds 中. bx+di+offset 指明偏移
    mov ax, [bp+si+offset] // 段基址在 ss 中. bp+si+offset 指明偏移
    mov ax, [bp+di+offset] // 段基址在 ss 中. bp+di+offset 指明偏移

    指明数据长度

  • 通过寄存器名指明要处理的数据的尺寸
  • // 使用字长度 (ax: 16bit)
    mov ax, 1
    mov ds:[0], ax

    // 使用字节长度 (al: 8bit)
    mov al, 1
    mov ds:[0], al

  • 在没有寄存器名存在的情况下, 使用操作符 Type ptr 指明内存单元长度. Type 可以使 word 或者 byte.
  • // 使用字长度 (ax: 16bit)
    mov word ptr ds:[0], 1
    add word ptr [bx], 1

    // 使用字节长度 (al: 8bit)
    mov byte ptr ds:[0], 1
    add byte ptr [bx], 1

  • 有些指令有默认的访问数据长度. 比如 push 就只能进行字操作
  • div指令

    注意问题:

  • 除数: 有 8 位和 16 位两种, 在一个 reg 或者内存单元中
  • 被除数: 默认放在 AX 或者 DX 和 AX 中, 如果除数为 8 位, 被除数则为 16 位, 默认在 AX 中; 如果除数为 16 位, 被除数则为 32 位, 在 DX 和 AX 中存放, DX 存放高 16 位, AX 存放低 16 位.
  • 结果: 如果除数为 8 位, 则 AL 存放除法操作的商, AH 存放余数; 如果除数为 16 位, 则 AX 存放除法操作的商, DX 存放余数;
  • 欢迎交流任何想法.

    End…