鱼C论坛

 找回密码
 立即注册

汇编语言课后作业

热度 2已有 1298 次阅读2016-7-14 16:22 |个人分类:汇编语言

《汇编语言》   王爽著  近期打算学习该本著作,遂将该书的课后习题答案放在这里
第一章 检测点1.1

11CPU的寻址能力为8KB,那么它的地址总线的宽度为 13位。

21KB的存储器有 1024 个存储单元,存储单元的编号从 0 1023

31KB的存储器可以存储 81922^13bit 1024Byte

41GB 1073741824 2^30Byte1MB 10485762^20Byte1KB 10242^10Byte

5808080888029680386的地址总线宽度分别为16根、20根、24根、32根,则它们的寻址能力分别为: 64 KB)、 1 MB)、 16 MB)、 4 GB)。

68080808880868028680386的数据总线宽度分别为8根、8根、16根、16根、32根。则它们一次可以传送的数据为: 1 B)、 1 B)、 2 B)、 2 B)、 4 B)。

7)从内存中读取1024字节的数据,8086至少要读 512 次,80386至少要读 256 次。

8在存储器中,数据和程序以 二进制 形式存放。(新理解的东东)

自己做的时候(2)(3) (4)出错,原因还是没有深刻认识到1Byte和1bit的区别,1Byte = 8 bit, Byte指的是字节;bit是比特,一个二进制位。
通过做题,熟悉了2^10 Byte= 1024 Byte = 1 KB; 2^20 Byte 1024^2 Byte = 1MB; 2^30 Byte 1024^3 Byte = 1GB; 
地址总线的宽度决定了CPU的寻址能力; 32位的地址总线能寻址4GB的内存;8080的地址总线为16根,寻址能力为64K;8088地址总线为20根,寻址能力为1M;80286地址总线为24根,寻址能力为16M;80386地址总线为32根,寻址能力为4G;
数据总线的宽度决定了CPU与其它器件进行数据传送时的一次传输数据量;8080,8088数据总线的宽度为8根,一次可传输1个字节;8086,80286数据总线的宽度为16根,一次可传输2个字节;80386数据总线的宽度为32根,一次可传输4个字节。
控制总线宽度决定了CPU对系统中其它器件的控制能力;

第二章 检测点 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条指令,编程计算24次方。

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

CFflag的第0位,进位标志位,无符号数 运算结果有进/借位,CF=1

CF(carry flag)    NC(no carrry):CF = 0    CY(carry): CF = 1

PFflag的第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

ZFflag的第6位,零标志位,判断结果是否为0,结果为0ZF=1

ZF(zero flag)  NZ(no zero):ZF = 0   ZR(zero): ZF = 1

SFflag的第7位,符号标志位,有符号数 运算结果为负数,SF=1

SF(0Symbol flag)  PL(plus): SF = 0   NG(negative):SF=1

OFflag的第11位,溢出标志位,有符号数 运算结果溢出,OF=1

OF(overflow flag)   NV(no overflow): OF = 0   OV(overflow): OF = 1

DFflag的第10位,方向标志位,DF=0 每次操作后 si,di递增,DF=1 每次操作后 si,di递减

DF(direction flag)   UP(up):DF = 0  DN(down): DF = 1

TFflag的第8位,TF=1,产生单步中断,引发中断过程

TF(trace flag)   

IFflag的第9位,IF=1CPU响应中断,引发中断过程,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.



路过

鸡蛋
2

鲜花

握手

雷人

刚表态过的朋友 (2 人)

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 立即注册

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-26 17:03

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

返回顶部