开学三周,王爽的《汇编语言》(第三版)总算是基本上看完了,本文是总结的第二部分,包括了书本上的实验

实验1 查看CPU和内存,用机器指令和汇编指令编程

  1. 使用Debug,将下面的程序段写入内存,逐条执行,观察每条指令执行后,CPU中相关寄存器的变化。

    机器码汇编指令执行后相关寄存器变化
    b8 20 4emov ax, 4E20HAX=4E20H
    05 16 14add ax, 1416HAX=6236H
    bb 00 20mov bx, 2000HBX=2000H
    01 d8add ax, bxAX=8236H
    89 c3mov bx, axBX=8236H
    01 d8add ax, bxAX=046CH
    b8 1a 00mov ax, 001AHAX=001AH
    bb 26 00mov bx, 0026HBX=0026H
    00 d8add al, blAX=0040H
    00 dcadd ah, blAX=2640H
    00 c7add bh, alBX=4026H
    b4 00mov ah, 0AX=0040H
    00 d8add al, blAX=0066H
    04 9cadd al, 9CHAX=0002H

    提示,可用E命令和A命令以两种方式将指令写入内存。注意用T命令执行时,CS:IP的指向。

  2. 将下面3条指令写入从2000:0开始的内存单元中,利用这3条指令计算2的8次方。

    1
    2
    3
    mov ax, 1
    add ax, ax
    jmp 2000:0003

    每次执行 add ax, ax 相当于将ax乘2,重复执行该条指令8次即可。

  3. 查看内存中的内容。
    PC机主板上的ROM写有一个生产日期,在内存FFF00H~FFFFFH的某几个单元中,请找到这个生产日期并试图改变它。
    提示,如果读者对实验的结果感到疑惑,请仔细阅读第1章中的1.15节。

通过Debug中的D命令,可以观察到生产日期以MM/DD/YY的格式存储在内存的ffff:0005-ffff:000c共计8个字节处。
该生产日期不可被修改,因为其只读。

  1. 向内存从B8100H开始的单元中填写数据,如:
    1
    -e B810:0000 01 01 02 02 03 03 04 04
    请读者先填写不同的数据,观察产生的现象;再改变填写的地址,观察产生的现象。
    提示,如果读者对实验的结果感到疑惑,请仔细阅读第1章中的1.15节。

通过向内存中的显存地址空间写入数据,控制在屏幕上的不同位置显示不同颜色的字符。

实验2 用机器指令和汇编指令编程

  1. 使用Debug,将下面的程序段写入内存,逐条执行,根据指令执行后的实验运行情况填空。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    mov ax, ffff
    mov ds, ax

    mov ax, 2200
    mov ss, ax

    mov sp, 1000

    mov ax,[0] ;ax = _____
    add ax,[2] ;ax = _____
    mov bx,[4] ;bx = _____
    add bx,[6] ;bx = _____

    push ax ;sp = _____ 修改的内存单元的地址是_____内容为_____
    push bx ;sp = _____ 修改的内存单元的地址是_____内容为_____
    pop ax ;sp = _____ ax = _____
    pop bx ;sp = _____ bx = _____

    push [4] ;sp = _____ 修改的内存单元的地址是_____内容为_____
    push [6] ;sp = _____ 修改的内存单元的地址是_____内容为_____

    结果(不唯一):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    D4EA
    25EE
    3002
    5F37
    00FE 220FE 25EE
    00FC 220FC 5F37
    00FE 5F37
    0100 25EE
    00FE 220FE 3002
    00FC 220FC 2F35
  2. 仔细观察图3.19中的实验过程,然后分析:为什么2000:0~2000:f中的内容会发生改变?
    在使用T命令进行单步追踪的时候,产生了中断,为了保护现场,CPU将PSW、CS和IP依此入栈,导致了内存相关位置内容的改变。

实验3 编程、编译、连接、跟踪

  1. 将下面的程序保存为t1.asm文件,将其生成可执行文件t1.exe。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    assume cs:codesg

    codesg segment
    mov ax, 2000H
    mov ss, ax
    mov sp, 0
    add sp, 10
    pop ax
    pop bx
    push ax
    push bx
    pop ax
    pop bx

    mov ax, 4c00h
    int 21h
    codesg ends

    end

    结果:

    1
    2
    3
    edit t1.asm
    masm.exe t1.asm;
    link.exe t1.obj;
  2. 用Debug跟踪t1.exe的执行过程,写出每一步执行后,相关寄存器中的内容和栈顶的内容。

    汇编指令相关寄存器的内容栈顶的内容
    mov ax, 2000HAX = 2000H00B8H
    mov ss, axSS = 2000H_____
    mov sp, 0SP = 00000H
    add sp, 10SP = 100000H
    pop axAX = 0 SP = 120000H
    pop bxBX = 0 SP = 140000H
    push axSP = 120000H
    push bxSP = 100000H
    pop axAX = 0 SP = 120000H
    pop bxBX = 0 SP = 140000H
    mov ax, 4c00hAX = 4C00H0000H
    int 21h__________

    结果不唯一

  3. PSP的头两个字节是CD 20,用Debug加载t1.exe,查看PSP的内容。

    1
    -d 2119:0

    2119为CS-0010H

实验4 [bx]和loop的使用

  1. 编程,向内存0:200~0:23F依此传送数据0~63(3FH)。

  2. 编程,向内存0:200~0:23F依此传送数据0~63(3FH),程序中只能使用9条指令,9条指令中包括“mov ax, 4c00h”和“int 21h”。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    assume cs:code
    code segment
    mov ax, 0020h
    mov ds, ax
    mov bx, 0
    mov cx, 64

    s: mov [bx], bl
    inc bl
    loop s

    mov ax, 4c00h
    int 21h
    code ends
    end
  3. 下面的程序的功能是将“mov ax, 4c00h”之前的指令复制到内存的0:200处,补全程序,上机调试,跟踪运行结果。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    assume cs:code
    code segment
    mov ax, _____
    mov ds, ax
    mov ax, 0020h
    mov es, ax
    mov bx, 0
    mov cx, _____
    s: mov al, [bx]
    mov es:[bx], al
    inc bx
    loop s
    mov ax, 4c00h
    int 21h
    code ends
    end

    结果:

    1
    2
    code
    18H

    提示:
    复制的是什么?从哪里到哪里?
    复制的是代码段中mov ax, 4c00h之前的代码,以数据的形式,从内存中代码段的位置复制到内存中0:200处开始的一段连续的空间。
    复制的是什么?有多少个字节?你如何直到要复制的字节的数量?
    可以用offset计算得出,也可以在Debug中用T命令观察得出。

实验5 编写、调试具有多个段的程序

  1. 将下面的程序编译连接,用Debug加载、跟踪,然后回答问题。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    assume cs:code, ds:data, ss:stack

    data segment
    dw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h
    data ends

    stack segment
    dw 0, 0, 0, 0, 0, 0, 0, 0
    stack ends

    code segment
    start: mov ax, stack
    mov ss, ax
    mov sp, 16

    mov ax, data
    mov ds, ax

    push ds:[0]
    push ds:[2]
    pop ds:[2]
    pop ds:[0]

    mov ax, 4c00h
    int 21h
    code ends

    end start

    ①CPU执行程序,程序返回前,data段中的数据为多少?
    ②CPU执行程序,程序返回前,CS = _____、SS = _____、DS = _____。
    ③设程序加载后,code段的段地址为X,则data段的段地址为_____,stack段的段地址为_____。
    答案:
    ①data段中的数据不变。
    ②212B、212A、2129(答案不唯一)
    ③X-2、X-1

  2. 将下面的程序编译连接,用Debug加载、跟踪,然后回答问题。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    assume cs:code, ds:data, ss:stack

    data segment
    dw 0123h, 0456h
    data ends

    stack segment
    dw 0, 0
    stack ends

    code segment
    start: mov ax, stack
    mov ss, ax
    mov sp, 16

    mov ax, data
    mov ds, ax

    push ds:[0]
    push ds:[2]
    pop ds:[2]
    pop ds:[0]

    mov ax, 4c00h
    int 21h
    code ends

    end start

    (1)CPU执行程序,程序返回前,data段中的数据为多少?
    (2)CPU执行程序,程序返回前,CS = _____、SS = _____、DS = _____。
    (3)设程序加载后,code段的段地址为X,则data段的段地址为_____,stack段的段地址为_____。
    (4)对于如下定义的段:

    1
    2
    3
    name segment
    ...
    segment ends

    如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为_____。
    答案:
    (1)data段中的数据不变。
    (2)212B、212A、2129(答案不唯一)
    (3)X-2、X-1
    (4)((N-1)/16 + 1)*16 其中除法为整除

  3. 将下面的程序编译连接,用Debug加载、跟踪,然后回答问题。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    assume cs:code, ds:data, ss:stack

    code segment
    start: mov ax, stack
    mov ss, ax
    mov sp, 16

    mov ax, data
    mov ds, ax

    push ds:[0]
    push ds:[2]
    pop ds:[2]
    pop ds:[0]

    mov ax, 4c00h
    int 21h
    code ends

    data segment
    dw 0123h, 0456h
    data ends

    stack segment
    dw 0, 0
    stack ends

    end start

    (1)CPU执行程序,程序返回前,data段中的数据为多少?
    (2)CPU执行程序,程序返回前,CS = _____、SS = _____、DS = _____。
    (3)设程序加载后,code段的段地址为X,则data段的段地址为_____,stack段的段地址为_____。
    答案:
    (1)data段中的数据不变。
    (2)2129、212D、212C(答案不唯一)
    (3)X+3、X+4

  4. 如果将1. 2. 3.题中的最后一条伪指令“end start”改为“end”(也就是说,不指明程序的入口),则哪个程序仍然可以正确执行?请说明原因。
    答案:
    只有程序3可以正确运行,在不指明程序入口的情况下,程序默认按照顺序从头开始执行,而3个程序中只有程序3的code段位于最开始的部分,所以只有程序3可以正确运行。

  5. 程序如下,编写code段中的代码,将a段和b段中的数据依此相加,将结果存到c段中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    assume cs:code
    a segment
    db 1, 2, 3, 4, 5, 6, 7, 8
    a ends

    b segment
    db 1, 2, 3, 4, 5, 6, 7, 8
    b ends

    c segment
    db 0, 0, 0, 0, 0, 0, 0, 0
    c ends

    code segment
    start:
    ?
    code ends
    end start

    答案:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    start:  mov ax, a
    mov ds, ax
    mov ax, b
    mov es, ax
    mov ax, c
    mov ss, ax
    mov bx, 0
    mov cx, 8
    s: mov al, [bx]
    add al, es:[bx]
    mov ss:[bx], al
    inc bx
    loop s
    mov ax, 4c00h
    int 21h
  6. 程序如下,编写code段中的代码,用push指令将a段中的前8个字型数据,逆序存储到b段中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    assume cs:code

    a segment
    dw 1, 2, 3, 4, 5, 6, 7, 8, 9, 0ah, 0bh, 0ch, 0dh, 0eh, 0fh, 0ffh
    a ends

    b segment
    dw 0, 0, 0, 0, 0, 0, 0, 0
    b ends

    code segment
    start:
    ?
    code ends

    end start

    答案:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    start:  mov ax, b
    mov ss, ax
    mov sp, 16
    mov ax, a
    mov ds, ax
    mov bx, 0
    mov cx, 8
    s: push [bx]
    add bx, 2
    loop s
    mov ax, 4c00h
    int 21h

实验6 实践课程中的程序

  1. 将课程中所有讲解过的程序上机调试,用Debug跟踪其执行过程,并在过程中进一步理解所讲内容。

  2. 编程,完成问题7.9中的程序。
    程序如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    assume cs:codesg, ss:stacksg, ds:datasg
    stacksg segment
    dw 0, 0, 0, 0, 0, 0, 0, 0
    stacksg ends

    datasg segment
    db '1. display '
    db '2. brows '
    db '3. replace '
    db '4. modify '
    datasg ends

    codesg segment
    start: mov ax, datasg
    mov ds, ax
    mov ax, stacksg
    mov ss, ax
    mov sp, 16
    mov bx, 0
    mov cx, 4
    s: push cx
    mov cx, 4
    mov si, 0
    s0: mov al, [bx + si + 3]
    and al, 11011111b
    mov [bx + si + 3], al
    inc si
    loop s0
    add bx, 16
    pop cx
    loop s
    mov ax, 4c00h
    int 21h
    codesg ends
    end start

实验7 寻址方式在结构化数据访问中的应用

编程,将data段中的数据按如下格式写入到table段中,并计算21年中的人均收入(取整),结果也按照下面的格式保存在table段中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
assume cs:codesg, ss:stack

stack segment
dw 8 dup (0)
stack ends

data segment
db '1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982', '1983'
db '1984', '1985', '1986', '1987', '1988', '1989', '1990', '1991', '1992'
db '1993', '1994', '1995'

dd 16, 22, 382, 1356, 2390, 8000, 16000, 24486, 50065, 97479, 140417, 197514
dd 345980, 590827, 803530, 1183000, 1843000, 2759000, 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

table segment
db 21 dup ('year summ ne ?? ')
table ends

codesg segment
start: mov ax, stack
mov ss, ax
mov sp, 16
mov ax, table
mov ds, ax
mov ax, data
mov es, ax
mov bx, 0
mov si, 0
mov cx, 21
year: push cx
mov cx, 4
mov di, 0
char: mov al, es:[si]
mov [bx+di], al
inc si
inc di
loop char
add bx, 16
pop cx
loop year
mov cx, 21
mov bx, 0
income: mov ax, es:[si]
mov [5+bx], ax
add si, 2
mov ax, es:[si]
mov [7+bx], ax
add si, 2
add bx, 16
loop income
mov cx, 21
mov bx, 0
staff: mov ax, es:[si]
mov [10+bx], ax
add si, 2
add bx, 16
loop staff
mov cx, 21
mov bx, 0
average:mov ax, [bx+5]
mov dx, [bx+7]
div word ptr [bx+10]
mov [13+bx], ax
add bx, 16
loop average
mov ax, 4c00h
int 21h
codesg ends
end start

实验8 分析一个奇怪的程序

分析下面的程序,在运行前思考,这个程序可以正确返回吗?
运行后再思考:为什么是这种结果?
通过这个程序加深对相关内容的理解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
assume cs:codesg
codesg segment
mov ax, 4c00h
int 21h
start: mov ax, 0
s: nop
nop
mov di, offset s
mov si, offset s2
mov ax, cs:[si]
mov cs:[di], ax
s0: jmp short s
s1: mov ax, 0
int 21h
mov ax, 0
s2: jmp short s1
nop
codesg ends
end start

分析:
这个程序可以正确返回,程序的入口为mov ax, 0,注意到指令jmp short s1占2字节,于是指令mov di, offset s将s的偏移地址传送到寄存器DI,mov si, offset s2将s2的偏移地址传送到SI,然后再通过通用寄存器ax做中转将s2处的指令复制到s处,最后再跳转至s处执行复制过来的指令。
注意jmp short s1是相对跳转,其直接修改IP寄存器,从s2到s1共有8个字节的偏移,实际上 jmp short s1等价于(ip)=(ip)-8,通过Debug可知第一个nop指令的偏移地址为8,所以再执行了复制过的指令后,IP将指向0,程序按照顺序执行mov ax, 4c00h和int 21h,正确返回。

实验9 根据材料编程

编程:在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串’welcome to masm!’。
编程所需的只是通过阅读、分析下面的材料获得。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
assume ds:data, cs:code

data segment
db 'welcome to masm!'
data ends

code segment
start: mov ax, data
mov ds, ax
mov ax, 0B800H
mov es, ax

mov bx, 1664
mov si, 0
mov cx, 16
char1: mov al, [si]
mov ah, 10000010B
mov es:[bx], ax
add bx, 2
inc si
loop char1

mov bx, 1824
mov si, 0
mov cx, 16
char2: mov al, [si]
mov ah, 10100100B
mov es:[bx], ax
add bx, 2
inc si
loop char2

mov bx, 1984
mov si, 0
mov cx, 16
char3: mov al, [si]
mov ah, 11110001B
mov es:[bx], ax
add bx, 2
inc si
loop char3

mov ax, 4C00H
int 21H
code ends
end start

实验10 编写子程序

  1. 显示字符串

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    assume cs:code, ss:stack

    stack segment
    dw 16 dup (0)
    stack ends

    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 ax, stack
    mov ss, ax
    mov sp, 32
    mov si, 0
    call show_str

    mov ax, 4c00h
    int 21h

    show_str:
    push cx
    push bx
    push ax
    push si
    push di
    push es
    ;using cx, bx, ax, si, di, es
    mov ax, 0b800h
    mov es, ax
    mov bx, 0
    mov di, 0
    mov al, 160
    mul dh
    add bx, ax
    mov al, 2
    mul dl
    add bx, ax ;bx stores address of start character
    mov al, cl ;al stores the color of character
    char: mov ch, 0
    mov cl, ds:[si]
    jcxz zero
    mov ch, al
    mov es:[bx+di], cx
    add di, 2
    inc si
    jmp char
    zero: pop es
    pop di
    pop si
    pop ax
    pop bx
    pop cx
    ret

    code ends
    end start
  2. 解决除法溢出的问题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    assume cs:code, ss:stack

    stack segment
    dw 16 dup (0)
    stack ends

    code segment
    start: mov ax, stack
    mov ss, ax
    mov sp, 32
    mov ax, 4240h
    mov dx, 000fh
    mov cx, 0ah
    call divdw

    mov ax, 4c00h
    int 21h

    divdw: push bx

    mov bx, ax ; bx stores L
    mov ax, dx ; ax stores H
    mov dx, 0
    div cx ; after div, ax holds int(H/N), dx holds rem(H/N)
    push ax ; push int(H/N) temporarily
    mov ax, bx ; ax stores L
    div cx
    mov cx, dx
    pop dx

    pop bx
    ret

    code ends
    end start
  3. 数值显示

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    assume cs:code, ss:stack

    stack segment
    dw 16 dup (0)
    stack ends

    data segment
    db 10 dup (0)
    data ends

    code segment
    start: mov ax, data
    mov ds, ax
    mov ax, stack
    mov ss, ax
    mov sp, 32
    mov ax, 12666
    mov si, 0
    call dtoc

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

    mov ax, 4c00h
    int 21h

    dtoc: push ax
    push si
    push di
    push dx
    push bx
    push cx
    mov di, 0
    mov dx, 0
    mov bx, 10

    devide: mov cx, ax
    jcxz stop
    div bx
    inc di
    push dx
    mov dx, 0
    jmp devide
    stop: mov cx, di
    string: pop bx
    add bx, 30h
    mov [si], bl
    inc si
    loop string

    pop cx
    pop bx
    pop dx
    pop di
    pop si
    pop ax
    ret

    show_str:
    push cx
    push bx
    push ax
    push si
    push di
    push es
    ;using cx, bx, ax, si, di, es
    mov ax, 0b800h
    mov es, ax
    mov bx, 0
    mov di, 0
    mov al, 160
    mul dh
    add bx, ax
    mov al, 2
    mul dl
    add bx, ax ;bx stores address of start character
    mov al, cl ;al stores the color of character
    char: mov ch, 0
    mov cl, ds:[si]
    jcxz zero
    mov ch, al
    mov es:[bx+di], cx
    add di, 2
    inc si
    jmp char
    zero: pop es
    pop di
    pop si
    pop ax
    pop bx
    pop cx
    ret

    code ends
    end start

实验11 编写子程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
assume cs:code

stack segment
dw 8 dup (0)
stack ends

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

code segment
begin: mov ax, stack
mov ss, ax
mov sp, 16
mov ax, data
mov ds, ax
mov si, 0
call letterc

mov ax, 4c00h
int 21h

letterc:
push cx
push si
pushf

mov ch, 0
start: mov cl, ds:[si]
jcxz zero
cmp cl, 97
jb next
cmp cl, 122
ja next
sub cl, 20h
mov ds:[si], cl
next: inc si
jmp start

zero: popf
pop si
pop cx
ret

code ends
end begin

实验12 编写0号中断的处理程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
assume cs:code

code segment
start:
mov ax, cs
mov ds, ax
mov si, offset do0

mov ax, 0
mov es, ax
mov di, 200h

mov cx, offset do0end - offset do0

cld

rep movsb

mov ax, 0
mov es, ax
mov word ptr es:[0], 200h
mov word ptr es:[2], 0

mov ax, 4c00h
int 21h

do0:
jmp short do0start
db "overflow!"
do0start:
mov ax, cs
mov ds, ax
mov si, 202h
mov ax, 0b800h
mov es, ax
mov di, 12*160+36*2
mov cx, 9
s:
mov al, [si]
mov es:[di], al
inc si
add di, 2
loop s

mov ax, 4c00h
int 21h
do0end:
nop

code ends
end start

实验13 编写、应用中断例程

  1. 编写并安装int 7ch中断例程,功能为显示一个用0结束的字符串,中断例程安装在0:200处。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    assume cs:code

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

    mov ax, 0
    mov es, ax
    mov word ptr es:[7ch * 4], 200h
    mov word ptr es:[7ch * 4 + 2], 0
    mov ax, 4c00h
    int 21h

    print:
    push es
    push ax
    push cx
    push dx
    push si
    push di

    mov ax, 0b800h
    mov es, ax
    mov al, 160
    mov ah, 0
    mul dh
    mov di, ax
    add dl, dl
    mov dh, 0
    add di, dx

    mov al, cl
    printstart:
    mov ch, 0
    mov cl, [si]
    jcxz zero
    mov ch, al
    mov es:[di], cx
    add di, 2
    inc si
    jmp printstart

    zero:
    pop di
    pop si
    pop dx
    pop cx
    pop ax
    pop es
    iret
    printend:
    nop

    code ends

    end start
  2. 编写并安装int 7ch中断例程,功能为完成loop指令功能。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    assume cs:code

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

    mov ax, 0
    mov es, ax
    mov word ptr es:[7ch * 4], 200h
    mov word ptr es:[7ch * 4 + 2], 0
    mov ax, 4c00h
    int 21h

    lp: push bp
    mov bp, sp
    dec cx
    jcxz lpret
    add [bp + 2], bx
    lpret: pop bp
    iret
    lpend: nop

    code ends

    end start
  3. 下面的程序,分别在屏幕的第2、4、6、8行显示4句英文诗,补全程序。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    assume cs:code
    code segment
    s1: db 'Good,better,best,', '$'
    s2: db 'Never let it rest,', '$'
    s3: db 'Till good is better,', '$'
    s4: db 'And better,best.', '$'
    s: dw offset s1, offset s2, offset s3, offset s4
    row: db 2, 4, 6, 8

    start: mov ax, cs
    mov ds, ax
    mov bx, offset s
    mov si, offset row
    mov cx, 4
    ok: mov bh, 0
    mov dh, _____
    mov dl, 0
    mov ah, 2
    int 10h

    mov dx, _____
    mov ah, 9
    int 21h
    _________
    _________
    loop ok
    mov ax, 4c00h
    int 21h
    code ends
    end start

    答案:

    1
    2
    3
    4
    [si]
    [bx]
    add bx, 2
    inc si

实验14 访问CMOS RAM

编程,以”年/月/日 时:分:秒”的格式,显示当前的日期,时间。
注意:CMOS RAM中存储着系统的配置信息,出了保存时间信息的单元外,不要向其他的单元中写入内容,否则将引起一些系统错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
assume cs:code, ds:data

data segment
s db 9, 8, 7, 4, 2, 0
data ends
code segment
start: mov ax, 0b800h
mov es, ax
mov di, 160 * 12
mov ax, data
mov ds, ax
mov si, 0
mov cx, 6

print: mov al, s[si]
out 70h, al
in al, 71h
call number
cmp si, 2
jb slash
je space
cmp si, 5
jb colon
next: inc si
loop print

mov ax, 4c00h
int 21h

;al->number, es:di->begin
number: push cx
mov ah, al
mov cl, 4
shr ah, cl
and al, 00001111b
add ah, 30h
add al, 30h
mov byte ptr es:[di], ah
mov byte ptr es:[di + 2], al
add di, 4
pop cx
ret

slash: mov byte ptr es:[di], '\'
add di, 2
jmp next

colon: mov byte ptr es:[di], ':'
add di, 2
jmp next

space: mov byte ptr es:[di], ' '
add di, 2
jmp next

code ends

end start

实验15 安装新的int 9中断例程

安装一个新的int 9中断例程,功能:在DOS下,按下’A’键后,除非不再松开,如果松开,就显示满屏幕的’A’;其他键照常处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
assume cs:code

stack segment
db 128 dup (0)
stack ends

code segment
start: mov ax, stack
mov ss, ax
mov sp, 128

push cs
pop ds

mov ax, 0
mov es, ax

mov si, offset int9
mov di, 204h
mov cx, offset int9end - offset int9
cld
rep movsb

push es: [9 * 4]
pop es: [200h]
push es: [9 * 4 + 2]
pop es: [202h]

cli
mov word ptr es: [9 * 4], 204h
mov word ptr es: [9 * 4 + 2], 0
sti

mov ax, 4c00h
int 21h

int9: push ax
push bx
push cx
push es

in al, 60h

pushf
call word ptr cs:[200h]

cmp al, 9eh
jne int9ret

mov ax, 0b800h
mov es, ax
mov bx, 0
mov cx, 2000
s: mov byte ptr es:[bx], 'A'
add bx, 2
loop s

int9ret:pop es
pop cx
pop bx
pop ax
iret

int9end:nop

code ends
end start

实验16 编写包含多个功能子程序的中断例程

安装一个新的int 7ch中断例程,为显示输出提供如下功能子程序

  1. 清屏
  2. 设置前景色
  3. 设置背景色
  4. 向上滚动一行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
assume cs:code

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

mov ax, 0
mov es, ax
mov word ptr es:[7ch * 4], 200h
mov word ptr es:[7ch * 4 + 2], 0
mov ax, 4c00h
int 21h

screen: jmp short set
;考虑到安装中断例程后偏移地址发生了变化,需要重新计算相关的偏移地址
table dw offset sub1 - offset screen + 200h, offset sub2 - offset screen + 200h, offset sub3 - offset screen + 200h, offset sub4 - offset screen + 200h

set: push bx

cmp ah, 3
ja sret
mov bl, ah
mov bh, 0
add bx, bx

;同上
call word ptr cs:(table - screen + 200h)[bx]

sret: pop bx
iret

sub1: push bx
push cx
push es
mov bx, 0b800h
mov es, bx
mov bx, 0
mov cx, 2000
sub1s: mov byte ptr es:[bx], ' '
add bx, 2
loop sub1s
pop es
pop cx
pop bx
ret

sub2: push bx
push cx
push es

mov bx, 0b800h
mov es, bx
mov bx, 1
mov cx, 2000
sub2s: and byte ptr es:[bx], 11111000B
or es:[bx], al
add bx, 2
loop sub2s

pop es
pop cx
pop bx
ret

sub3: push bx
push cx
push es
mov cl, 4
shl al, cl
mov bx, 0b800h
mov es, bx
mov bx, 1
mov cx, 2000
sub3s: and byte ptr es:[bx], 10001111B
or es:[bx], al
add bx, 2
loop sub3s
pop es
pop cx
pop bx
ret

sub4: push cx
push si
push di
push es
push ds

mov si, 0b800h
mov es, si
mov ds, si
mov si, 160
mov di, 0
cld
mov cx, 24
sub4s: push cx
mov cx, 160
rep movsb
pop cx
loop sub4s

mov cx, 80
mov si, 0
sub4s1: mov byte ptr [160*24+si], ' '
add si, 2
loop sub4s1

pop ds
pop es
pop di
pop si
pop cx
ret

screenend:
nop

code ends
end start

参考王爽《汇编语言》实验16:包含多个功能子程序的中断例程 解答
可以用伪指令org x简化该程序
org x表明接下来的指令从偏移地址x开始
修改后的相关指令如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
org 200h
screen: jmp short set

table dw sub1, sub2, sub3, sub4

set: push bx

cmp ah, 3
ja sret
mov bl, ah
mov bh, 0
add bx, bx

call word ptr table[bx]

实验17 编写包含多个功能子程序的中断例程

安装一个新的int 7ch中断例程,实现通过逻辑扇区号对软盘进行读写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
assume cs:code

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

mov ax, 0
mov es, ax
mov word ptr es:[7ch * 4], 200h
mov word ptr es:[7ch * 4 + 2], 0
mov ax, 4c00h
int 21h

floppyio:
push ax
push cx
push dx

add ah, 2
mov al, 1
push ax ;计算相应的ah和al并压栈
mov ax, dx
mov dx, 0
mov cx, 1440
div cx ;计算逻辑扇区号/1440
push ax ;将商即面号压栈
mov ax, dx
mov dl, 18
div dl ;计算逻辑扇区号/1440的余数/18
inc ah
mov ch, al
mov cl, ah ;设置相应的ch和cl
pop ax ;将相应的面号出栈
mov dh, al
mov dl, 0 ;设置相应的dh和dl
pop ax ;将相应的ah和al出栈
int 13h ;调用13h例程进行实际的读写

pop dx
pop cx
pop ax
iret
floppyioend:
nop

code ends
end start