开学三周,王爽的《汇编语言》(第三版)总算是基本上看完了,本文是总结的第一部分,包括了书上所有的检测点答案

第一章 基础知识

检测点 1.1

  1. 1个CPU的寻址能力为8KB,那么它的地址总线的宽度为____。
    13
    解析:CPU在内存中寻址的最小单位是Byte(字节),8KB = 2^13B,因此地址总线的宽度为13.
  2. 1KB的存储器有____个存储单元。存储单元的编号从____到____。
    1024 0 1023
  3. 1KB的存储器可以存储____个bit,____个Byte。
    2^13 2^10
  4. 1GB、1MB、1KB分别是____________Byte
    2^30 2^20 2^10
  5. 8080、8088、80286、80386的地址总线宽度分别为16根、20根、24根、32根,则他们的寻址能力分别为____(KB)、____(MB)、____(MB)、____(GB)。
    64 1 16 4
  6. 8080、8088、8086、80286、80386的数据总线宽度分别为8根、8根、16根、16根、32根。则它们一次可以传送的数据为:____(B)、____(B)、____(B)、____(B)、____(B)。
    1 1 2 2 4
  7. 从内存中读取1024字节的数据,8086至少要读取____次,80386至少要读取____次。
    512 256
  8. 在存储器中,数据和程序以____形式存放。
    二进制

第二章 寄存器

检测点 2.1

  1. 写出每条汇编指令执行后相关寄存器中的值
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    mov ax, 62627		AX =
    mov ah, 31H AX =
    mov al, 23H AX =
    add ax, ax AX =
    mov bx, 826CH BX =
    mov cx, ax CX =
    mov ax, bx AX =
    add ax, bx AX =
    mov al, bh AX =
    mov ah, bl AX =
    add ah, ah AX =
    add al, 6 AX =
    add al, al AX =
    mov ax, cx AX =
    F4A3H 31A3H 3123H 6246H 826CH 6246H 826CH 04D8H 0482H 6C82H D882H D888H D810H 6246H
  2. 只能使用目前学过的汇编指令,最多使用4条指令,编程计算2的4次方。
    1
    2
    3
    4
    mov ax, 2
    add ax, ax
    add ax, ax
    add ax, ax

检测点 2.2

  1. 给定段地址为0001H,仅通过变化偏移地址寻址,CPU的寻址范围为_____到_____。
    00010H到1000FH
  2. 有一数据存放在内存20000H的单元中,现给定段地址为SA,若想用偏移地址寻到此单元。则SA应满足的条件是:最小为_____,最大为_____。提示,反过来思考一下,当段地址给定为多少,CPU无论怎么变化偏移地址都无法寻到20000H单元?
    1001F 2000H
    20000H - 0FFFFH = 10001H
    20000H - 00000H = 20000H

检测点 2.3

下面的3条指令执行后,CPU几次修改IP?都是在什么时候?最后IP中的值是多少?

1
2
3
mov ax, bx
sub ax, ax
jmp ax

修改了四次:

  1. 第1条指令执行后,IP指向第2条指令
  2. 第2条指令执行后,IP指向第3条指令
  3. 第3条指令执行后,IP指向第4条指令
  4. JMP指令执行后,IP重新指向第1条指令

第三章 寄存器(内存访问)

检测点 3.1

  1. 在Debug中,用“d 0:0 1f”查看内存,结果如下。

    1
    2
    0000:0000 70 80 F0 30 EF 60 30 E2-00 80 80 12 66 20 22 60
    0000:0010 62 26 E6 D6 CC 2E 3C 3B-AB BA 00 00 26 06 66 88

    下面的程序执行前,AX=0,BX=0,写出每条汇编指令执行完后相关寄存器中的值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    mov ax, 1
    mov ds, ax
    mov ax, [0000] AX =
    mov bx, [0001] BX =
    mov ax, bx AX =
    mov ax, [0000] AX =
    mov bx, [0002] BX =
    add ax, bx AX =
    add ax, [0004] AX =
    mov ax, 0 AX =
    mov al, [0002] AX =
    mov bx, 0 BX =
    mov bl, [000C] BX =
    add al, bl AX =

    提示,注意ds的设置。

    2662H E626H E626H 2662H D6E6H FD48H 2C14H 0 00E6H 0 0026H 000CH

  2. 内存中的情况如图3.6所示。
    各寄存器的初始值:CS=2000H,IP=0,DS=1000H,AX=0,BX=0;
    (1)写出CPU执行的指令序列(用汇编指令写出)
    (2)写出CPU执行每条指令后,CS、IP和相关寄存器中的数值。
    (3)再次体会:数据和程序有区别吗?如何确定内存中的信息哪些是数据,哪些是程序?
指令 CS:IP DS AX BX
mov ax, 6622H 2000:3 1000H 6622H 0
jmp 0ff0:0100 2000:8->0ff0:0100 1000H 6622H 0
mov ax, 2000H 0ff0:0103 1000H 2000H 0
mov ds, ax 0ff0:0105 2000H 2000H 0
mov ax, [0008] 0ff0:0108 2000H C389H 0
mov ax, [0002] 0ff0:010B 2000H EA66H 0

程序和数据没有区别,本质上都是二进制01码,关键在于CPU如何解读。

检测点 3.2

  1. 补全下面的程序,使其可以将10000H~1000FH中的8个字,逆序复制到20000H~2000FH中。逆序复制的含义如图3.17所示(图中内存里的数据均为假设)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    mov ax, 1000H
    mov ds, ax
    __________
    __________
    __________
    push [0]
    push [2]
    push [4]
    push [6]
    push [8]
    push [A]
    push [C]
    push [E]

    答案:

    1
    2
    3
    mov ax, 2000H
    mov ss, ax
    mov sp, 0010H
  2. 补全下面的程序,使其可以将10000H~1000FH中的8个字,逆序复制到20000H~2000FH中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    mov ax, 2000H
    mov ds, ax
    __________
    __________
    __________
    pop [E]
    pop [C]
    pop [A]
    pop [8]
    pop [6]
    pop [4]
    pop [2]
    pop [0]

    答案:

    1
    2
    3
    mov ax, 1000H
    mov ss, ax
    mov sp, 0

第六章 包含多个段的程序

检测点 6.1

  1. 下面的程序实现依此用内存0:0-0:15单元中的内容改写程序中的数据,完成程序:

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

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

    start: mov ax, 0
    mov ds, ax
    mov bx, 0

    mov cx, 8
    s: mov ax, [bx]
    _________
    add bx, 2
    loop s

    mov ax, 4c00h
    int 21h

    codesg ends

    end start

    答案:

    1
    mov cs:[bx], ax
  2. 下面的程序实现依此用内存0:0-0:15单元中的内容改写程序中的数据,数据的传送用栈来进行。栈空间设置在程序内。完成程序:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    assume cs:codesg
    dw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h

    dw 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

    start: mov ax, ____
    mov ss, ax
    mov sp, ____

    mov ax, 0
    mov ds, ax
    mov bx, 0
    mov cx, 8
    s: push [bx]
    ____________
    add bx, 2
    loop s

    mov ax, 4c00h
    int 21h

    codesg ends

    end start

    答案:

    1
    2
    3
    cs
    24h
    pop cs:[bx]

第九章 转移指令的原理

检测点 9.1

  1. 程序如下

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

    data segment
    ___________
    data ends

    code segment
    start: mov ax, data
    mov ds, ax
    mov bx, 0
    jmp word ptr [bx+1]

    code ends
    end start

    若要使程序中的jmp指令执行后,CS:IP指向程序的第一条指令,在data段中应该定义哪些数据?
    答案:

    1
    dw 0, 0
  2. 程序如下

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

    data segment
    dd 12345678H
    data ends

    code segment

    start: mov ax, data
    mov ds, ax
    mov bx, 0
    mov [bx], ____
    mov [bx + 2], ____
    jmp dword ptr ds:[0]

    code ends

    end start

    补全程序,使jmp指令执行后,CS:IP指向程序的第一条指令。
    答案:

    1
    2
    bx
    cs

    注意:bx指向低位,bx+2指向高位,低位为IP,而高位为CS。

  3. 用Debug查看内存,结果如下:

    1
    2000:1000 BE 00 06 00 00 00 ......

    则此时,CPU执行指令:

    1
    2
    3
    mov ax, 2000H
    mov es, ax
    jmp dword ptr es:[1000H]

    后,(CS)=?,(IP)=?
    答案:
    (CS)=0006,(IP)=00BE

检测点 9.2

补全编程,利用jcxz指令,实现在内存2000H段中查找第一个值为0的字节,找到后,将它的偏移地址存储在dx中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
assume cs:code
code segment
start: mov ax, 2000H
mov ds, ax
mov bx, 0
s: __________
__________
__________
__________
jmp short s
ok: mov dx, bx
mov ax, 4c00h
int 21h
code ends
end start

答案:
1
2
3
4
mov cl, [bx]
mov ch, 0 ;注意这一步的必要性
jcxz ok
inc bx

检测点 9.3

补全编程,利用loop指令,实现在内存的2000H段中查找第一个值为0的字节,找到后,将它的偏移地址存储在dx中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
assume cs:code
code segment
start: mov ax, 2000H
mov ds, ax
mov bx, 0
s: mov cl, [bx]
mov ch, 0
_________
inc bx
loop s
ok: dec bx
mov dx, bx
mov ax, 4c00h
int 21h
code ends
end start

答案:
1
inc cx ;注意loop的工作原理

第十章 CALL和RET指令

检测点 10.1

补全程序,实现从内存1000:0000处开始执行指令。

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

stack segment
db 16 dup (0)
stack ends

code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov ax, ____
push ax
mov ax, ____
push ax
retf
code ends

end start

答案:
1
2
1000h
0

检测点 10.2

下面的程序执行后,ax中的数值为多少?

内存地址 机器码 汇编指令
1000:0 b8 00 00 mov ax,0
1000:3 e8 01 00 call s
1000:6 40 inc ax
1000:7 58 s: pop ax

ax中的数值为6,注意执行完call s后,IP先变为6,然后将IP的值压栈,最后跳转至s。

检测点 10.3

下面的程序执行后,ax中的数值为多少?

内存地址 机器码 汇编指令
1000:0 b8 00 00 mov ax,0
1000:3 9a 09 00 00 10 call far ptr s
1000:8 40 inc ax
1000:9 58 s: pop ax
add ax,ax
pop bx
add ax,bx

ax中的数值为1010H,注意执行完call far ptr s后,IP先变为8,然后将CS、IP的值分别为1000和8依此压栈,最后再跳转至s继续执行。

检测点 10.4

下面的程序执行后,ax中的数值为多少?

内存地址 机器码 汇编指令
1000:0 b8 06 00 mov ax,6
1000:3 ff d0 call ax
1000:5 40 inc ax
1000:6 58 mov bp,sp
add ax,[bp]

ax中的数值为0BH,分析方法类似检测点10.2

检测点 10.5

  1. 下面的程序执行后,ax中的数值为多少?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    assume cs:code
    stack segment
    dw 8 dup (0)
    stack ends
    code segment
    start: mov ax,stack
    mov ss,ax
    mov sp,16
    mov ds,ax
    mov ax,0
    call word ptr ds:[0eh]
    inc ax
    inc ax
    inc ax
    mov ax,4c00h
    int 21h
    code ends
    end start

    ax中的数值为3,注意ds与ss中存放的段地址相同,在执行了call word ptr ds:[0EH]之后,程序会先将下一条指令inc ax的偏移量压栈,然后跳转到栈顶所指向的指令的位置,即跳转至第一条inc ax的位置,故最后ax的值为3。
    注意:在使用Debug单步跟踪的时候,由于t命令所导致的中断,而影响了栈中的值。

  2. 下面的程序执行后,ax和bx中的数值为多少?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    assume cs:codesg
    data segment
    dw 8 dup (0)
    data ends
    code segment
    start: mov ax,data
    mov ss,ax
    mov sp,16
    mov word ptr ss:[0],offset s
    mov ss:[2],cs
    call dword ptr ss:[0]
    nop
    s: mov ax,offset s
    sub ax,ss:[0ch]
    mov bx,cs
    sub bx,ss:[0eh]
    mov ax,4c00h
    int 21h
    code ends
    end start

    ax中的数值为1,bx中的数值为0,注意到程序的一开始将a的偏移量和cs放入ss:[0]和ss:[2]中,然后调用call指令,将CS和IP(nop指令的偏移量)依此压栈后跳转到s处继续执行,ax最终为s的偏移量减去nop指令所在位置的偏移量,为1,bx最终为cs的段地址相减,为0。

第十一章 标志寄存器

检测点 11.1

写出下面每条指令执行后,ZF、PF、SF等标志位的值

指令 ZF PF SF
sub al, al 1 1 0
mov al, 1 1 1 0
push ax 1 1 0
pop bx 1 1 0
add al, bl 0 0 0
add bl, 10 0 1 0
mul al 0 1 0

检测点 11.2

写出下面每条指令执行后,ZF、PF、SF、CF、OF等标志位的值

指令 CF OF SF ZF PF
sub al, al 0 0 0 1 1
mov al, 10H 0 0 0 1 1
add al, 90H 0 0 1 0 1
mov al, 80H 0 0 1 0 1
add al, 80H 1 1 0 1 1
mov al, 0FCH 1 1 0 1 1
add al, 05H 1 0 0 0 0
mov al, 7DH 1 0 0 0 0
add al, 0BH 0 1 1 0 1

检测点 11.3

  1. 补全下面的程序,统计F000:0处32个字节中,大小在[32,128]的数据的个数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    	mov ax, 0f000h
    mov ds, ax

    mov bx, 0
    mov dx, 0
    mov cx, 32
    s: mov al, [bx]
    cmp al, 32
    __________
    cmp al, 128
    __________
    inc dx
    s0: inc bx
    loop s

    答案:

    1
    2
    jb s0
    ja s0
  2. 补全下面的程序,统计F000:0处32个字节中,大小在(32,128)的数据的个数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    	mov ax, 0f000h
    mov ds, ax

    mov bx, 0
    mov dx, 0
    mov cx, 32
    s: mov al, [bx]
    cmp al, 32
    __________
    cmp al, 128
    __________
    inc dx
    s0: inc bx
    loop s

    答案:

    1
    2
    jna s0
    jnb s0

检测点 11.4

下面的程序执行后:(ax)=?

1
2
3
4
5
6
7
8
9
mov ax, 0
push ax
popf ;将PSW置0(本章所学习的标志位都为0)
mov ax, 0fff0h
add ax, 0010h ;修改相关标志位
pushf
pop ax ;(将PSW保存至ax)
and al, 11000101B
and ah, 00001000B ;只考虑CF,PF,ZF,SF,OF五个标志位

答案:
(ax)=45H

第十二章 内中断

检测点 12.1

  1. 用Debug查看内存,情况如下:
    0000:0000 68 10 A7 00 8B 01 70 00-16 00 9D 03 8B 01 70 00
    则3号中断源对应的中断处理程序的入口地址为:____
    答案:
    0070:018B
    注意高地址存放段地址,低地址存放偏移地址

  2. 存储N号中断源对应的中断处理程序入口的偏移地址的内存单元的地址为:
    存储N号中断源对应的中断处理程序入口的段地址的内存单元的地址为:

    答案:4N,4N+2

第十三章 int指令

检测点 13.1

  1. 在上面的内容中,我们用7ch中断例程实现loop的功能,则上面的7ch中断例程所能进行的最大转移位移为多少?
    答案:65535

  2. 用7ch中断例程完成jmp near ptr s指令的功能,用bx向中断例程传送转移位移。
    答案:

    1
    2
    3
    4
    5
    jnp:	push bp
    mov bp, sp
    add [bp+2], bx
    pop bp
    iret

检测点 13.2

判断下面说法的正误:

  1. 我们可以编程改变FFFF:0处的指令,使得CPU不去执行BIOS中的硬件系统检测和初始化程序。
    错误:FFFF:0处的内容无法修改
  2. int 19h中断例程,可以由DOS提供。
    错误:此时DOS还未被引导

第十四章 端口

检测点 14.1

  1. 编程,读取CMOS RAM的2号单元的内容。
    1
    2
    3
    mov al, 2
    out 70h, 2
    in al, 71h
  2. 编程,向CMOS RAM的2号单元写入0。
    1
    2
    3
    4
    mov al, 2
    out 70h, 2
    mov al, 0
    out 71h, al

检测点 14.2

编程,用加法和位移指令计算(ax)=(ax)*10。
提示,(ax)*10=(ax)*2+(ax)*8。

1
2
3
4
5
mov bx, ax
shl ax, 1
mov cl, 3
shl bx, cx
add ax, bx

第十五章 外中断

检测点 15.1

  1. 仔细分析一下上面的int 9中断例程,看看是否可以精简一下?
    其实在我们的int 9中断例程中,模拟int指令调用原int 9中断例程的程序段是可以精简的,因为在进入中断例程后,IF和TF都已经置0,没有必要再进行设置了。对于程序段:

    1
    2
    3
    4
    5
    6
    7
    pushf
    pushf
    pop ax
    and ah, 11111100B
    push ax
    popf
    call dword ptr ds:[0]

    可以精简为:

    1
    2
    pushf
    call dword ptr ds:[0]

    两条指令。

  2. 仔细分析上面程序中的主程序,看看有什么潜在的问题?
    在主程序中,如果在执行设置int 9中断例程的段地址和偏移地址的指令之间发生了键盘中断,则CPU将转去一个错误的地址执行,将发生错误。
    找出这样的程序段,改写它们,排除潜在的问题。
    提示,注意sti和cli指令的用法。
    答案:

    1
    2
    3
    4
    cli
    mov word ptr es:[9*4],offset int9
    mov word ptr es:[9*4+2],cs
    sti

    以及:

    1
    2
    3
    4
    5
    6
    cli
    push ds:[0]
    pop es:[9*4]
    push ds:[2]
    pop es:[9*4+2]
    sti

第十六章 直接定址表

检测点 16.1

下面的程序将code段中a处的8个数据累加,结果存储到b处的双字中,补全程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
assume cs:code
code segment
a dw 1, 2, 3, 4, 5, 6, 7, 8
b dd 0
start: mov si, 0
mov cx, 8
s: mov ax, ____
add ____, ax
adc ____, 0
add si, ____
loop s

mov ax, 4c00h
int 21h

code ends
end start

答案:
1
2
3
4
a[si]
word ptr b[0]
word ptr b[2]
2

注意word ptr的使用

检测点 16.2

下面的程序将data段中a处的8个数据累加,结果存储到b处的字中,补全程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
assume cs:code, es:data

data segment
a db 1, 2, 3, 4, 5, 6, 7, 8
b dw 0
data ends

code segment
start: __________
__________
mov si, 0
mov cx, 8
s: mov al, a[si]
mov ah, 0
add b, ax
inc si
loop s

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

答案:
1
2
mov ax, data
mov es, ax

第十七章 使用BIOS进行键盘输入和磁盘读写

检测点 17.1

“在int 16h中断例程中,一定有设置IF=1的指令”,这种说法对吗?

正确,int 16h中断例程在键盘缓冲区中没有数据时,会等待直到键盘缓冲区中有数据为止,因此,int 16h中需要处理int 9h中断,所以一定有设置IF=1的指令。