《汇编语言》检测点笔记
之前一直觉得《汇编语言》很秀。Assembly Language 阿。本来下个学期选修想选那门“微机接口和汇编语言”。但这个学期以为要挂的选修课,老师还是给了面子。所以学分讲道理是够了。斟酌了一下,决定自己看书爽一爽《汇编》。
果断选择了王爽的《汇编语言 (第三版) 》。
因为是有习题的,所以把习题就顺便记录了下来。
前面 11 章的答案我都 debug 验证过了,网上的答案有很多错误。从 12 章开始,我开始瞎屁股浏览了。主要是因为前面 11 章的内容让我比较喜欢,后面的较多的理论元素和一些指令完善,我就粗略的学习了。
检测点1.1
- 1个 CPU 的寻址能力为 8KB,那么它的地址总线的宽度为
13
。 (8KB = 8 * 1024 = 2 ^ 13。 1字节为一个存储单元) - 1KB 的存储器有
1024
个存储单元。存储单元的编号从0
到1023
。 - 1KB 的存储器可以存储
2^13
个bit,个1024
Byte。 - 1GB, 1MB, 1KB 分别是
2^30
,2^20
,2^10
Byte。 - 8080,8088,80286,80386 的地址总线宽度分别为 16 根, 20 根, 24 根, 32 根,则它们的寻址能力分别为:
2^6
(KB) ,1
(MB),16
(MB),4
(GB)。 - 8080, 8088, 8086, 80286, 80386 的数据总线宽度分别为 8 根, 8 根, 16 根, 16 根, 32 根。则它们一次可以传送的数据为:
1
(B),1
(B),2
(B),2
(B),4
(B)。 - 从内存中读取 1024 字节的数据, 8086 至少要读
512
次, 80386至少要读256
次。 - 在存储器中, 数据和程序以
二进制
形式存放。
检测点2.1
写出每条汇编指令执行后相关寄存器中的值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14mov ax,62627 ; AX = `F4A3H`
mov ah,31H ; AX = `31A3H`
mov al,23H ; AX = `3123H`
add ax,ax ; AX = `6246H`
mov bx,826CH ; BX = `826CH`
mov cx,ax ; CX = `6246H`
mov ax,bx ; AX = `826CH`
add ax,bx ; AX = `04D8H`
mov al,bh ; AX = `0482H`
mov ah,bl ; AX = `6C82H`
add ah,ah ; AX = `D882H`
add al,6 ; AX = `D888H`
add al,al ; Ax = `D810H`
mov ax,cx ; AX = `6246H`用目前学过的汇编指令,最多使用 4 条指令,编程计算 2 的 4 次方。
1
2
3
4mov ax,2
add ax,ax
add ax,ax
add ax,ax
检测点2.2
- 给定段地址为 0001H, 仅通过变化偏移地址寻址,CPU 的寻址范围为
00010H
到1000FH
。 - 有一数据存放在内存 20000H 单元中,现给定段地址为 SA,若想用偏移地址寻到此单元。则 SA应满足的条件是: 最小为
1001H
,最大为20000H
。
检测点2.3
下面的三条指令执行后,CPU几次修改IP?都是在什么时候?最后IP中的值是多少?1
2
3mov ax,bx
sub ax,ax
jmp ax4次。每条执行完都修改一次加上一次 jmp 的修改。0。
检测点3.1
- 在Debug中, 用“d 0:0 1f” 查看内存,结果如下:下面的程序执行前,AX=0,BX=0,写出每条汇编指令执行完后相关寄存器中的值。
1
20000: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
1 | mov ax,1 |
- 内存中的情况如图3.6所示。
各寄存器的初始值: CS=2000H, IP=0, DS=1000H, AX=0, BX=0;
- 写出CPU执行的指令序列 (用汇编指令写出)
- 写出CPU执行每条指令后,CS,IP和相关寄存器中的数值。
1
2
3
4
5
6mov ax,6622H ; CS=2000H, IP=0003H, DS=1000H, AX=6622H, BX=0000H
jmp 0ff0:0100 ; CS=0FF0H, IP=0100H, DS=1000H, Ax=6622H, BX=0000H
mov ax,2000H ; CS=0FF0H, IP=0103H, DS=1000H, AX=2000H, BX=0000H
mov ds,ax ; CS=0FF0H, IP=0105H, DS=2000H, Ax=2000H, BX=0000H
mov ax,[0008] ; CS=0FF0H, IP=0108H, DS=2000H, AX=C389H, BX=0000H
mov ax,[0002] ; CS=0FF0H, IP=010BH, Ds=2000H, Ax=EA66H, BX=0000H - 再次体会: 数据和程序有区别吗?如何确定内存中的信息哪些是数据,哪些是程序?
没有区别。存储在数据段中就是数据,存储在程序段中就是程序。
检测点3.2
补全下面的程序,使其可以将 10000H~1000FH 中的八个字,逆序复制到 20000H~2000FH 中。逆序复制的含义如图3.17所示 (图中内存里的数据均为假设) 。 (图我就不贴了。不重要)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15mov ax,1000H
mov ds,ax
mov ax,2000H
mov ss,ax
mov sp,0
push [0]
push [2]
push [4]
push [6]
push [8]
push [A]
push [C]
push [E]补全下面的程序,使其可以将 10000H~1000FH 中的 8 个字,逆序复制到20000H~2000FH中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15mov ax,2000H
mov ds,ax
mov ax,1000H
mov ss,ax
mov sp,0
pop [E]
pop [C]
pop [A]
pop [8]
pop [6]
pop [4]
pop [2]
pop [0]检测点6.1
- 下面的程序实现依次用内存 0:0~0:15 单元中的内容改写程序中数据,完成程序:
1 | assume cs:codesg |
- 下面的程序实现依次用内存 0:0~0:15 单元中的内容改写程序中数据,数据的传送用栈来进行。栈空间设置在程序内。完成程序:
1 | assume cs:codesg |
ps:我调试的时候发现一件很骚的事情,就是调试的时候,栈空间的值会发生改变。主要是因为中断机制,中断的时候某些关键值要存在内存里。。就用了程序的栈空间。我还纳闷了半天。。
实验5
这个实验做完主要有两点总结:
第二题的第4小道:
16 * (N / 16 + 1)
。关于内存的问题。在16位机器上,不足16字节的数据按16字节存储,意思就是17个字节,在程序中其实占的是32字节。其它机器应该可以递推。编译器编译汇编文件,从上往下编译。同理,数据段要是写在代码段后面,执行加载到内存中时,在内存中的位置也在代码段的后面。
检测点9.1
- 程序如下:
1
2
3
4
5
6
7
8
9
10
11
12
13assume cs:code
data segment
db 8 dup(0)
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17assume cs:code
data segment
dd 12345678H
data ends
code segment
start: mov ax,data
mov ds,ax
mov bx,0
mov [bx],offset start
mov [bx+2],cs
jmp dword ptr ds:[0]
code ends
end start补全程序,使 jmp 指令执行后,CS: IP 指向程序的第一条指令。
用 Debug 查看内存,结果如下:
1
2000:1000 BE 00 06 00 00 00 ...
则此时,CPU 执行指令:
1
2
3mov ax,2000H
mov es,ax
jmp dword ptr es:[1000H]后, (CS) =
0060h
, (IP) =00BE
检测点9.2
补全程序,利用 jcxz 指令,实现在内存 2000H 段中查找第一个值为 0 的字节,找到后,将它的偏移地址存储在 dx 中。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17assume cs:code
code segment
start: mov ax,2000H
mov ds,ax
mov bx,0
s: mov cl,[bx]
mov ch,0 ; 注意寻找的是字节
jcxz short ok
inc bx
jmp short s
ok: mov dx,bx
mov ax,4c00h
int 21h
code ends
end start
检测点9.3
补全编程,利用 loop 指令,实现在内存 2000H 段中查找第一个值为 0 的字节, 找到后,将它的偏移地址存储在 dx 中。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18assume cs:code
code segment
start: mov ax,2000H
mov ds,ax
mov bx,0
s: mov cl,[bx]
mov ch,0
inc cx ; loop指令,将 cx 加一在判定是否为0
inc bx
loop s
ok: dec bx
mov dx,bx
mov ax,4c00h
int 21h
code ends
end start
检测点10.1
补全程序,实现从内存 1000:0000 处开始执行指令1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18assume cs:code
stack segment
db 16 dup(0)
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov ax,1000
push ax
mov ax,0000
push ax
retf
code ends
end start
检测点10.2
下面的程序执行后,ax 中的数值为多少?
内存地址 | 机器码 | 汇编指令
—|—|—
1000:0 | b8 00 00 | mov ax,0
1000:3 | e8 01 00 | call s
1000:6 | 40 | inc ax
1000:8 | 58 | s:pop ax
0006h
检测点10.3
下面的程序执行后,ax 中的数值为多少?1
2
3
4
5
6
7
8
9内存地址 | 机器码 | 汇编指令
---|---|---
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
1010h
检测点10.4
下面的程序执行后,ax 中的数值为多少?1
2
3
4
5
6
7内存地址 | 机器码 | 汇编指令
---|---|---
1000:0 | b8 06 00 | mov ax,6
1000:3 | ff d0 | call ax
1000:5 | 40 | inc ax
1000:6 | | mov bp,sp
add ax,[bp]
000Bh
检测点10.5
- 下面的程序执行后,ax 中的数值为多少? (注意: 用 call 指令的原理来分析,不要在 Debug 中单步跟踪来验证你的结论。对于此程序,在Debug中单步跟踪的结果,不能代表 CPU 的实际执行结果。)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18assume cs:code
stack segment
dw 8 dup(0)
stack segment
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
0003h
- 下面的程序执行后,ax 和 bx 中的数值为多少?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20assume cs:code
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 = 0001h
, bx = 0000h
检测点11.1
写出下面每条指令执行后,ZF,PF,SF等标志位的值。1
2
3
4
5
6
7sub al,al ; ZF= 1 ,PF= 1 ,SF= 0
mov al,1 ; ZF= 1 ,PF= 1 ,SF= 0
push ax ; ZF= 1 ,PF= 1 ,SF= 0
pop bx ; ZF= 1 ,PF= 1 ,SF= 0
add al,bl ; ZF= 0 ,PF= 0 ,SF= 0
add al,10 ; ZF= 0 ,PF= 1 ,SF= 0
mul al ; ZF= 0 ,PF= 1 ,SF= 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 | 0 |
mov al,80H | 0 | 0 | 1 | 0 | 0 |
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
- 补全下面的程序,统计 F:000:0 处 32 个字节中,大小在[32,128]的数据的个数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14mov ax,0f000h
mov ds,ax
mov bx,0
mov dx,0
mov cx,32
s: mov al,[bx]
cmp al,32
jb s0
cmp al,128
ja s0
inc dx
s0: inc bx
loop s - 补全下面程序中,统计 F:000:0 处 32 个字节中,大小在 (32,128) 的数据的个数。
1
2
3
4
5
6
7
8
9
10
11
12
13mov ax,0f000h
mov ds,ax
mov bx,0
mov dx,0
mov cx,32
s: mov al,[bx]
cmp al,32
jna s0
cmp al,128
jnb s0
inc dx
s0: inc bx
loop s
检测点11.4
下面的程序执行后: (ax) =?1
2
3
4
5
6
7
8
9mov ax,0
push ax
popf
mov ax,0fff0h
add ax,0010h
pushf
pop ax
and al,11000101B
and ah,00001000B
0045h
检测点12.1
用 Debug 查看内存,情况如下:
1
0000:0000 68 10 A7 00 8B 01 70 00-16 00 9D 03 8B 01 70 00
则 3 号中断源对应的中断处理程序的入口地址为:
0070h:018Bh
存储 N 号中断源对应的中断处理程序入口的偏移地址的内存单元的地址为:
[4N]
。
存储 N 号中断源对应的中断处理程序入口的段地址的内存单元的地址为:[4N+2]
。
检测点13.1
在上面的内容中,我们用 7ch 中断例程实现 loop 的功能,则上面的 7ch 中断例程所能进行的最大转移位移是多少?
-128~127
用 7ch 中断例程完成 jmp near ptr s 指令的功能,用 bx 向中断例程传送转移位移。
应用举例: 在屏幕的第 12 行,显示 data 段中以 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
49assume cs:code,ds:data
data segment
db 'conversation',0
data ends
code segment
start: mov ax,cs
mov ds,ax
mov si,offset show
mov ax,0
mov es,ax
mov di,200h
mov cx,offset showend-offset show
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,data
mov ds,ax
mov si,0
mov ax,0b800h
mov es,ax
mov di,12*160
s: cmp byte ptr [si],0
je ok
mov al,[si]
mov es:[di],al
mov al,2
mov es:[di+1],al
inc si
add di,2
mov bx,offset s-offset ok
int 7ch
ok: mov ax,4c00h
int 21h
show: push bp
mov bp,sp
add [bp+2],bx
pop bp
iret
showend:nop
code ends
end start
检测点13.2
错误,BIOS在ROM中 (READ ONLY) ,不能被更改
错误,19h中断,操作系统还未被引导。
检测点14.1
编程,读取 CMOS RAM 的 2 号单元的内容
1
2
3mov al,2
out 70h,al
in al,71h编程,向 CMOS RAM 的 2 号单元写入 0。
1
2
3
4mov al,0
out 71h,al
mov al,2
in 70h,al
检测点14.2
编程,用加法和移位指令计算 (ax) = (ax) 10。 (提示, (ax) 10= (ax)2+(ax)8)1
2
3
4
5
6mov ax,2
shl ax,1
mov bx,ax
shl ax,1
shl ax,1
add ax,bx
检测点15.1
- 精简2.
1
2pushf
call dword ptr ds:[0]在中断向量表中设置新的int9中断入口地址的时候不让其发生中断。
1
2
3
4cli
mov word ptr es:[9*4],offset int9
mov word ptr es:[9*4+2],cs
sti
恢复中断向量表int9的源地址时同理:
1
2
3
4
5
6cli
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
17assume 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,a[si]
add b,ax
abc b,0
add si,1
loop s
mov ax,4c00h
int 21h
code ends
end start
检测点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
22assume 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 ax,data
mov es,ax
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
检测点17.1
当执行int16中断时是从缓冲区中读出字符,若缓冲区为空,则int16应该可以响应int9的中断,故IF不一定为1