热度 2|
(1)1个CPU的寻址能力为8KB,那么它的地址总线的宽度为 13位。
(2)1KB的存储器有 1024 个存储单元,存储单元的编号从 0 到 1023 。
(3)1KB的存储器可以存储 8192(2^13) 个bit, 1024个Byte。
(4)1GB是 1073741824 (2^30) 个Byte、1MB是 1048576(2^20) 个Byte、1KB是 1024(2^10)个Byte。
(5)8080、8088、80296、80386的地址总线宽度分别为16根、20根、24根、32根,则它们的寻址能力分别为: 64 (KB)、 1 (MB)、 16 (MB)、 4 (GB)。
(6)8080、8088、8086、80286、80386的数据总线宽度分别为8根、8根、16根、16根、32根。则它们一次可以传送的数据为: 1 (B)、 1 (B)、 2 (B)、 2 (B)、 4 (B)。
(7)从内存中读取1024字节的数据,8086至少要读 512 次,80386至少要读 256 次。
(8)在存储器中,数据和程序以 二进制 形式存放。(新理解的东东)
第二章 检测点 2.1
(1) 写出每条汇编指令执行后相关寄存器中的值。
mov 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
开始做的时候把mov和add搞混了,导致出错,不知道自己的脑子是怎么了,明明很简单,下次细心细心!
(2) 只能使用目前学过的汇编指令,最多使用4条指令,编程计算2的4次方。
mov ax,2 AX=2
add ax,ax AX=4
add ax,ax AX=8
add ax,ax AX=16
检测点2.2
(1) 给定段地址为0001H,仅通过变化偏移地址寻址,CPU的寻址范围为 0010H 到 1000FH 。
(2) 有一数据存放在内存20000H单元中,现给定段地址为SA,若想用偏移地址寻到此单元。则SA应满足的条件是:最小为 1001H ,最大为 2000H 。
当段地址给定为 1001H 以下和 2000H 以上,CPU无论怎么变化偏移地址都无法寻到20000H单元
这两道题还是全对!噢噢也!
汇总一下第二章知识点:
一个字(word)等于两个字节(byte),一个字节等于8为bit位
0000H刚好是一个字!
一个段地址的起始地址必然是16的倍数,而且一个段的长度最大为64KB。
段寄存器:
CS:Code Segment 代码段寄存器 DS:Data Segment 数据段寄存器
SS:Stack Segment 堆栈段寄存器 ES:Extra Segment 附加段寄存器
实验一: 查看CPU和内存,用机器指令和汇编指令编程
这块主要熟悉了汇编指令 -r 查看各类寄存器的状态 -r CS -r ip 等可以改变相应寄存器的值
-d 1000:0 F 查看对应内存的机器指令 默认查看128字节
-e 改写内存中的内容
-u 以汇编指令的形式查看内存中的内容
-t 执行一条机器指令
-a 以汇编指令的格式在内存中写入一条机器指令
向地址 A0000~BFFFF的内存单元写数据,就是向显存中写入数据,会直接显示卡到显示器上
例: -e B810:0000 01 01 02 02 03 03 04 04 在Debug界面就可以看到有个笑脸状在屏幕上
向C0000~FFFFF的内存单元中写入数据的操作是无效的,这等于改写只读存储器中的内容。
ROM的生产日期在:FFFF0H~FFFFFH这几个单元里,但是尝试修改它是没有效果的。
第三章
问题3.1 问题3.2 问题3.3 学到的知识
我们将起始地址为N的字单元简称为N地址字单元。 注意地址的高低顺序:如0字单元存放的内容为:4E20H;
用MOV al,[0] [0]表示的是偏移地址,它的段地址存放在DS中,规定DS(段寄存器)不能直接传如数据,如 MOV DS,1000H 这行程序就会报错,非法,因此我们常通过一个普通的寄存器给DS里面传入数据: MOV BX,1000H MOV DS,BX 再接着将AL中的数据传如内存10001中
MOV [1],AL
SUB指令为减
【骚人小技巧】 将ax清零:sub ax,ax 比mov ax,0要好,sub命令占两个字节,mov命令占三个字节
交换值:如果要交换连个寄存器ax,bx的值,可以采用栈,push ax push bx pop ax pob bx ok!
Debug的T命令在执行修改寄存器SS的指令时,下一条指令也紧跟着被执
检测点3.1 (一)
(二)
指令序列 |
CS |
IP |
DS |
AX |
BX | |
初始值 |
2000h |
0 |
0 |
0 |
0 | |
1 |
mov ax,6622h |
2000h |
3h |
0 |
6622h |
0 |
2 |
jmp 0ff0:0100 |
ff0h |
100h |
0 |
6622h |
0 |
3 |
mov ax,2000h |
ff0h |
103h |
0 |
2000h |
0 |
4 |
mov ds,ax |
ff0h |
105h |
2000h |
2000h |
0 |
5 |
mov ax,[8] |
ff0h |
108h |
2000h |
c389h |
0 |
6 |
mov ax,[2] |
ff0h |
10bh |
2000h |
ea66h |
0 |
检测点3.2 (一) (二)
实验二:用机器指令和汇编指令编程
(二)
自己理解:
前提:改变了SS,SP(栈顶指针)的值
2000:000E 存放的是当前CS的数据
2000:000C 存放的是当前IP的数据
接下来对比下正式答案:
前面说过,执行MOV SS,AX时,接着会执行MOV SP,0010
在单步执行的时候MOV SP,0010不会显示出来,这是由于使用的中断机制的原因
那么,在这里也是一样
因为在DEBUG使用T等指令引发了中断造成的,中断过程使用当前栈空间存放CPU关键数据,所以,你的栈里有些不是你操作的数据了
这个问题后面会学到
因为如果是在中断过程中压栈使栈越界的话,在Windows的命令窗口会强制关闭的。这个可能在你跟踪一些程序的时候会遇到,到时候有个思考方向。
第四章
实验四
具体的寄存器状态就不一一截图了,手动过一遍比较好。
学到的知识点:
dos系统下command命令加载你的程序,程序会被加载在一段内存里,找到一段起始地址为SA:0000(主要是偏移地址为0)的容量足够大的空闲内存区,个人认为这片内存区应该是随机找的,在这片内存区的前256字节中,创建一个程序段前缀(PSP)的数据区,DOS要利用PSP来和被加载程序进行通信,这个SA的地址就是DS的地址,SA+10H就是代码段,也就是CS的地址了,又上面的截图可以看出DS=0B2D,CS=DS+10H=0B3D;由CS:IP指向你的程序入口,这时command就放弃了CPU的控制权,CPU立即开始运行程序,直至程序结束,command重新取得CPU的控制权。
command在DOS中成为命令解释器,也就是DOS系统的shell。
第五章
学到的知识点:
(一)debug下mov ax,[1] 会解释为将DS:0001中的数据赋值给AX,而在masm汇编编译器中mov ax,[1]会解释为mov ax,1
为了避免这样的歧义出现,建议以后再写masm的源程序时,mov ax,[1]改为显式书写 mov ax,ds:[1]或者借助其他的寄存器来实现,如mov bx,1 mov ax,[bx]
(二)有时候,我们需要直接向一段内存中写入内容,但这段内存空间不应存放系统或其他程序的数据和代码,否则写入操作很可能引发错误;在DOS方式下,一般情况,0:200~0:2ff空间内没有系统或其它程序或代码;以后,我们需要直接向一段内存中写入内容时,就使用0:200~0:2ff这段空间
(三)“ds”,"cs","ss","es",在汇编语言中成为段前缀。
可以这样写:mov ax,cs:[0] mov ax,es:[0] mov ax,ds:[0] mov ax,ss:[0]
不能这样写:mov ax,bx:[0] 段地址:偏移地址,其中段地址只能由段前缀来表示
(四)复制什么数据到哪去,一般指的是字节型数据,要注意在赋值时:mov al,[0] 用al而不用ax,字宽不一样,切记,切记
实验四:(一)(二)自己写时都是以传统方式写的循环,赋值,答案给的第一问竟然以循环,压栈完成,简直拍案叫绝,给力
(一)以循环,压栈完成
assume cs:code
code segment
mov bx,20h
mov ss,bx
mov sp,40h
mov bx,3f3eh
mov cx,32
s: push bx
sub bx,202h
loop s
mov ax,4c00h
int 21h
code ends
end
(二)以循环,赋值完成
assume cs:code
code segment
mov ax,0020h
mov ds,ax
mov bx,0
mov cx,64
s: mov [bx],bl
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end
(三)
首先明确是复制mov ax,4c00h之前的指令到0:0200处,从mov ax,cs复制到loop s
其次,明确mov ax,cs是mov 寄存器和寄存器,占两个字节;mov ax,0020H是mov 寄存器和立即数,占3个字节;loop s ,占两个字节;push ax,占1个字节;inc bx ,占一个字节;sub cx,6,占3个字节;int 21h,占两个字节;mov es:[bx],al占3个字节
最后,由masm进入debug 调试程序,cx中的值并不为0,cx中的内容时该程序所占字节的大小
所以,由于填写答案的不同,就出现三个版本
版本一:mov ax,cs sub cx,5 mov ax,4c00h 占3个字节 int 21h占两个字节,cx中的内容时该程序所占字节的大小,减去不用复制指令的字节,就ok了
assume cs:code
code segment
mov ax,cs
mov ds,ax
mov ax,0020h
mov es,ax
mov bx,0
sub cx,5
s: mov al,[bx]
mov es:[bx],al
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end
版本二:mov ax,cs mov cx 23 或mov cx 17H 从从mov ax,cs复制到loop s,共占23(17H)字节
assume cs:code
code segment
mov ax,cs
mov ds,ax
mov ax,0020h
mov es,ax
mov bx,0
mov cx,17h
s: mov al,[bx]
mov es:[bx],al
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end
版本三:mov ax,code mov cx 24 或mov cx 18H 从从mov ax,cs复制到loop s,共占24(18H)字节
code在此处相当于立即数
assume cs:code
code segment
mov ax,code
mov ds,ax
mov ax,0020h
mov es,ax
mov bx,0
mov cx,17h
s: mov al,[bx]
mov es:[bx],al
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end
第六章
实验5 (一)
(二)
(三)
(四)
(3)题可以执行,如果不指明入口位置,则程序从所分配的控件开始执行,前两个是数据段,只有从第3条开始是指令代码
(五)代码如下:
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: 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,0
add al,ds:[bx]
add al,es:[bx]
mov ss:[bx],al
inc bx ;add bx,1(第一次写成这个,太占内存,改掉)
loop s
mov ax,4c00h
int 21h
code ends
end start
(六)代码如下:
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: mov ax,a
mov ds,ax
mov ax,b
mov ss,ax
mov sp,16
mov bx,0
mov cx,8
s: push [bx]
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end start
第七章
上机实现各节课后习题,程序太多,限于篇幅,截图吧
编程,完成7.9中的程序
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,0000h
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
第八章
试验七:寻址方式在结构化数据访问中的应用
自己写的,题目并不算难,就是还有待优化的空间,跟答案一比较,还是有差距
assume cs:codesg
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'
;以上是表示21年的21个字符串
dd 16,22,382,1356,2390,8000,16000,14486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,184300,2759000,3753000,4649000,5937000
;以上是表示21年公司总收入的21个dword型数据
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
;以上是表示21年公司雇员人数的21个word型数据
data ends
table segment
db 21 dup ('year summ ne ?? ')
table ends
codesg segment
start: mov ax,data
mov ds,ax
mov ax,table
mov es,ax
mov si,0
mov di,0
mov bx,0
mov cx,21
s: mov bx,ds:[si]
mov es:[di],bx
mov bx,ds:[si+2]
mov es:[di+2],bx
add si,4
add di,16
loop s
;以上为将表示21年的21个字符串复制到table中的year位置
mov si,84
mov di,5
mov bx,0
mov cx,21
s0: mov bx,ds:[si]
mov es:[di],bx
mov bx,ds:[si+2]
mov es:[di+2],bx
add si,4
add di,16
loop s0
;以上为将表示21年公司总收入的21个dword型数据复制到table中的summ位置
mov si,168
mov di,10
mov bx,0
mov cx,21
s1: mov bx,ds:[si]
mov es:[di],bx
add si,2
add di,16
loop s1
;以上为将表示21年公司雇员人数的21个word型数据复制到table中的ne位置
mov si,84
mov di,168
mov bx,0
mov cx,21
mov bp,13
s3: mov ax,ds:[si]
mov dx,ds:[si+2]
div word ptr ds:[di]
mov es:[bp],ax
add si,4
add di,2
add bp,16
loop s3
;以上为将表示21年公司雇员人数的21个word型数据复制到table中的ne位置
mov ax,4c00h
int 21h
codesg ends
end start
在这道题调试过程中,要是一步GO到mov ax,4c00h(程序结尾)处,再查询状态,是没有问题的,但是要是使用G命令先执行到某一循环的一半,在G到循环结束,再查看状态,就会出现第一处数据的出错,并不知道这是为什么
拿着答案的程序调试下,依旧也是这样,待有空整理后来填坑
出错结果如下:
第九章
检测点9.1 (一)
(二)
(三)
检测点9.2
检测点9.3
实验8:分析一个奇怪的程序
这个题实际上就是靠jmp 跳转它是根据位移进行的,程序由start开始执行,执行到mov cs:[di],ax时,
将S2处的机器码赋给s:处,机器码为EBF6,其中F6为JMP的位移值,位移为-10(f6为-10的补码)
接着程序向下执行 s0:处 jmp short s
就会跳到S(ip = 0008H):处执行EBF6机器码,首先ip=ip+2=10,接着跳转,IP = IP + 位移(-10) = 0
就跳到CS:0处执行mov ax,4c00h int 21h
然后程序就会正确返回喽。(注意执行到Int 21h的时候用p命令,前面学过,别忘了)
截图一张:
实验9:根据材料编程
由于实验9比较挠人,所以写了篇帖子进行分析,链接如下:
http://bbs.fishc.com/forum.php?mod=viewthread&tid=75792&extra=page%3D1%26filter%3Dtypeid%26typeid%3D379
第十章
检测点10.1
检测点10.2
检测点10.3
检测点10.4
检测点10.5 (一)
(二)
第十一章
这章的寄存器让我拖的时间有点长,自己惰性是一方面,中途又出了趟差,前后又耽搁一下,足足拖了一个月,真是不可饶恕,静下心来,好好看。
觉得这几个寄存器还是比较容易混的,个人认为用英语助记会好很多,也就是说,我们要知道寄存器的缩写的是什么英文单词,现整理如下:
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
0 0 0 0 of df if tf sf zf 0 af 0 pf 0 cf
CF是flag的第0位,进位标志位,无符号数 运算结果有进/借位,CF=1
CF(carry flag) NC(no carrry):CF = 0 CY(carry): CF = 1
PF是flag的第2位,奇偶标志位,运算结果二进制数中1的个数为偶数,PF=1
PF(parity flag) PO(parity odd):PF = 0 PE(parity even):PF = 1
AF是flag的第4位,辅助进位标志位,AF=1 在字操作时,发生低字节向高字节进位或借位时;在字节操作时,发生低4位向高4位进位或借位时
AF(Auxiliary carry flag) AC(assistant carry) :AF = 1 NA(no assistant carry):AF = 0
ZF是flag的第6位,零标志位,判断结果是否为0,结果为0,ZF=1
ZF(zero flag) NZ(no zero):ZF = 0 ZR(zero): ZF = 1
SF是flag的第7位,符号标志位,有符号数 运算结果为负数,SF=1
SF(0Symbol flag) PL(plus): SF = 0 NG(negative):SF=1
OF是flag的第11位,溢出标志位,有符号数 运算结果溢出,OF=1
OF(overflow flag) NV(no overflow): OF = 0 OV(overflow): OF = 1
DF是flag的第10位,方向标志位,DF=0 每次操作后 si,di递增,DF=1 每次操作后 si,di递减
DF(direction flag) UP(up):DF = 0 DN(down): DF = 1
TF是flag的第8位,TF=1,产生单步中断,引发中断过程
TF(trace flag)
IF是flag的第9位,IF=1,CPU响应中断,引发中断过程,IF=0,不响应可屏蔽中断
IF(Interrupt flag) EI(enable interrupt): IF = 1 DI(disable interrupt): IF= 0
还有之前的寄存器的英文全称
AH&AL=AX(accumulator):累加寄存器
BH&BL=BX(base):基址寄存器
CH&CL=CX(count):计数寄存器
DH&DL=DX(data):数据寄存器
SP(Stack Pointer):堆栈指针寄存器
BP(Base Pointer):基址指针寄存器
SI(Source Index):源变址寄存器
DI(Destination Index):目的变址寄存器
IP(Instruction Pointer):指令指针寄存器
CS(Code Segment)代码段寄存器
DS(Data Segment):数据段寄存器
SS(Stack Segment):堆栈段寄存器
ES(Extra Segment):附加段寄存器
OF overflow flag 溢出标志 操作数超出机器能表示的范围表示溢出,溢出时为1.
SF sign Flag 符号标志 记录运算结果的符号,结果负时为1.
ZF zero flag 零标志 运算结果等于0时为1,否则为0.
小黑屋|手机版|Archiver|鱼C工作室
( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)
GMT+8, 2025-5-11 16:49
Powered by Discuz! X3.4
© 2001-2023 Discuz! Team.