王爽汇编 (习题解答)

检测点1.1
1
寻址能力为8KB
那么寻址范围就是0 --- 8191
8192 = 2^X
X = 13 这就是寻址宽度

2
1bit = 8byte
1024byte = 1kb
1kb = 1024 * 1(byte) * 8(bit) = 8192 bit     CPU存储器有1024个存储单元
单元编号从0到1023

3
1bit = 8byte
1024byte = 1kb
8192 bit  1024byte

4
1bit = 8byte
1024byte = 1kb
1024kb  =  1MB
1024MB  =  1GB
8589934592    8388608   8192
1073741824    1048576   1024
  2^30          2^20     2^10

5
X = 16 这就是寻址宽度
2^16=65536(byte)   64KB
2^20=1048576 1MB
2^24=16777216 16MB
2^32=4294967296(byte)/1024=4194304(KB)/1024=4096(MB)/1024= 4(GB)

6
一根数据线传送1位bit(0或1)
8根=1byte  8根=1byte  16根=2byte  16根=2byte  32根=4byte

7
16根数据线读1024byte  512次
32根数据线读1024byte  256次

8
全部都是0或1 二进制
=====================================================
检测点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 <---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

2
2^4 = 2*2*2*2 = 1*2*2*2*2 = 16
MOV AX,2    AX=0002H 2^1
ADD AX,AX   AX=0004H 2^2
ADD AX,AX   AX=0008H 2^3
ADD AX,AX   AX=0016H 2^4
======================================================
检测点2.2
1
段地址:0001H * 16 = 00010H
偏移地址:0000H ~ FFFFH
寻址范围:00010H+0000H = 00010H ~ 00010H+FFFFH = 1000FH

2
物理地址:20000H
段地址SA:2000H * 10 + 0000H
段地址SA:1001H * 10 + EFFFH

=======================================================
检测点2.3
mov ax,bx  ax=bx
sub ax,ax  ax=0000H
jmp ax     ip=0000H

=======================================================
检测点3.1
1.
0000:0010     0001:0000
00000          00010
+0010          +0000
--------     -----------
00010          00010

mov ax,1
mov ds,ax       ds=0001H                        <-----DS值
MOV AX,[0000]   AX=0001:0000(62 26) ax=2662H
mov bx,[0001]   bx=0001:0001(26 e6) bx=e626H
mov ax,bx       ax=e626H
mov ax,[0000]   ax=0001:0000(62 26) ax=2662H
mov bx,[0002]   bx=0001:0002(e6 d6) dx=d6e6H
add ax,bx       ax=2662H + d6e6H = fd48H
add ax,[0004]   ax=fd48H + 0001:0004(cc 2e)= fd48 +2ecc = 2c14H
mov ax,0        ax=0
mov al,[0002]   al=0 + 0001:0002(e6)  ax=00e6H
mov bx,0        bx=0
mov bl,[000c]   bl=0 + 0001:000c(26)  bx=0026H
add al,bl       al=e6 + 26            ax=000cH

2.
CS=2000H  IP=0000   DS=1000H  AX=0  BX=0
MOV AX,6622H  ax=6622H  IP=0003
JMP OFFO:0100  CS=0FF0  IP=0100   地址为:10000H
mov ax,2000H  ax=2000H  IP=0103
mov ds,ax     ds=2000H  IP=0105
MOV AX,[0008] AX=2000:0008(89 C1) AX=C189H  IP=0108 (答案文档中写AX=C389 不知道搞什么,原题不一样?)
MOV AX,[0002] AX=2000:0002(66 EA) AX=EA66H  IP=010B   
======================================================
检测点3.2
1 逆序拷贝
mov ax,1000H
mov ds,ax     设置1000:? 为数据段
mov ax,2000H
mov ss,ax     设置2000:? 为栈段
mov sp,0010   指向栈顶元素2000:0010
2
mov ax,2000H
mov ds,ax     设置2000:? 为数据段
MOV ax,1000H
mov ss,ax
mov sp,0000   设置1000:0为栈顶元素

实验题
mov ax,[0]  ax = 5bea
add ax,[2]  ax = 5cca
mov bx,[4]  bx = 30f0
add bx,[6]  bx = 6023
push ax     sp = 00fe  修改的内存单元地址是2200:00fe 内容为 ca 5c
push bx     sp = 00fc  修改的内存单元地址是2000:00fc 内容为 23 60
pop  ax     sp = 00fe  ax = 6023
pop  bx     sp = 0100  bx = 5cca
push [0004] sp = 00fe  修改的内存单元地址是2200:00fe 内容为 f0 30
push [0006] sp = 00fc  修改的内存单元地址是2200:00fc 内容为 64 10

mov ax,2000
mov ss,ax
mov sp,10     2000:0010  2000:0010 堆栈
mov ax,3123
push ax       200fe 33  200ff 0c
mov ax,3366   200fc 26  200fd 0d  
push ax       26 0d 33 0c
=============================================
实验3
assume cs:codesg
codesg segment
       mov ax,2000H  AX=2000  IP=0003
       mov ss,ax     SS=2000  自动执行下一句后sp=0
       mov sp,0
       add sp,4      sp=0004  SS:SP指向栈顶元素2000:0004
       pop ax        ax=2000:04= NTVDM CPU 遇到无效的指令CS:0000 IP:0077 OP:F0 37 05 10 02 程序异常退出
       pop bx          (根据下面的解释,大致认为是DEBUG进行单步跟踪时候,暂停被加载程序时会做保护现场处理,那么就会有入栈
       push ax          操作,栈空间刚好又是当前SS:SP。现场保护完成后估计会重定位栈顶元素,
       push bx          所以当我们做出栈操作时,就会破坏现场或者是栈顶越界。于是程序就被杀死了。)
       pop ax
       pop bx
       mov ax,4c00h
       int 21h
codesg ends
end

DS=0B4D CS=0B50 IP=0000 SS=0B5D SP=0000 
在windows系列操作系统环境下,我们进入的cmd或command都是工作在保护模式下的DOS操作系统的虚拟机,在保护模式下,windows操作系统要对程序执行的优先权以及程序访问内存空间的权限和方式进行控制或者说限制,如果有违反这些限制规范的用户进程执行,那么windows的安全机制为了保证操作系统的正常运转,就要杀死这个进程,并提示错误信息。
在这里首先声明这里的pop ax指令是没有语法错误的,在DOS实模式下随时都有效可执行;但是它用在不合理的地方,就会出现逻辑错误(导致栈顶超界),这种逻辑错误实模式DOS操作系统是不予理睬的,它的安全机制相对薄弱,逻辑错误的出现要靠人来发现,排除。但是在保护模式下,进行push栈操作或pop栈操作时,一旦出现栈顶超界状况,即会被工作在这个模式下的操作系统(如windows系列的)得知,并进行相应处理。

找到产生非法操作的原因:栈顶超界;
避免栈顶超界状况的出现有两种:
1、把栈顶位置设置合理;
2、合理的使用栈操作指令push 和 pop 。

问题2、栈空间里没有内容,此时能弹堆栈?
-----------------------------------------------------------------------------------------
首先说什么是栈空间,栈空间无非是一段由SS:SP指示的内存空间而已,一般情况下我们能够用栈操作指令访问它,当然,我们也可以用访问内存地址的任何一种合理方式访问这段空间。其次,我们说 栈空 表明的意思是:栈顶设置之初,我们没有栈操作的时候,这段空间的数据我们是未知的,所以通常也是没有用的,但是并不代表这时栈顶SS:SP所指向的内存字单元中没有数据!再有一点:无论是push还是pop操作,栈的操作在任何情况下都是有效的(但不一定在任何情况下都是合理的,对于不合理的栈操作正如问题 1 的回答中所讲,会有操作系统的干预。)


回到楼主的问题:

对于以上问题(栈顶没有处在0000偏移地址位置,一次栈操作不会发生栈超界,但为什么出现错误信息提示)的出现我是这样理解的:
这种情况出现在debug跟踪像楼上的朋友贴出来的那样的程序的时候,由于栈顶设置的位置接近一个内存段的开始位置,我们在使用debug的 T 命令进行单步跟踪,debug执行T命令的过程大体是:
1、设置控制程序执行的相关状态字(保证执行被加载程序的一条指令后,暂停程序后面语句的执行),执行权交给被加载程序;
2、执行被加载程序的当前指令,当然,紧接着的语句由于步骤 1 的设置不能获得执行,执行权就又交给了debug;
3、debug负责显示各寄存器状态及相关信息的子程序块执行:
a、保存当前被加载程序的状态,即保存相关寄存器的状态等信息(保存位置:栈空间;实现方式:入栈操作);
b、显示各寄存器的状态(a步骤后栈中的某些数据)及相关信息(下一条指令);
c、恢复各寄存器状态(出栈操作),等待下一个debug命令的输入。
对于以上过程,稍加分析可知栈空间的位置(寄存器SS中的内容)在这个过程中是不能够也不允许发生变化的,所以a步骤中的栈操作也发生在被加载程序使用的栈空间内,这时,如果栈顶的位置离栈段开始位置较近且a步骤中栈操作的次数相对较多,就难免会发生栈顶超界现象了。
来源于Wednesday
修改方法:add sp,4改成add sp,天于6的数
个人认为debug 时引起中断要保存Flags,cs,ip三个寄存器的内容故要大于6.
============================================================================================
实验4
1.和2.
assume    cs:codesg
      codesg segment
            
              MOV       AX,0020h
              MOV       DS,AX
              MOV       BX,0000h
             
              MOV       CX,64           因为是0 ~ 63 所以是64次
           s: MOV       DS:[BX],Bl
              INC       Bl
              LOOP      s
                          
              MOV       AX,4c00h
              INT       21h
      codesg ENDS
END

3.
ASSUME    CS:code
              code SEGMENT
              MOV       AX,code      code 对应 CS 也就是程序的第一条指令
              MOV       DS,AX
              MOV       AX,0020H
              MOV       ES,AX
              MOV       BX,0000h
             
              MOV       CX, 24       通过调试程序 查看CX初始值为1D。通过内存查看到中断语句长度为5H。运算得出。
            s:MOV       AL,[BX]
              MOV       ES:[BX],AL
              INC       BX
              LOOP      s
             
              MOV       AX,4c00h
              INT       21h
             
              code ENDS
END

=======================================================================
检测点6.1
1.
mov  cs:[bx],ax
2.
mov  ax,cs
mov  sp,26
pop  ss:[bx]

=====================================================================
实验5
1.
DATA段数据未变
CS=0B65H  SS=0B64H  DS=0B63 除DS均未变
code(cs)段地址为X(0b65H) data(ds)为X-2(0B63)(初试DS加上10字节的PSP区)  stack(ss)为x-1(0b64)
2.
DATA段数据未变
CS=0B65H  SS=0B64H  DS=0B63 除DS均未变
code(cs)段地址为X(0b65H) data(ds)为X-2(0B63)(初试DS加上10字节的PSP区)  stack(ss)为x-1(0b64)
(N/16+1)*16 [说明:N/16只取整数部分]
3.
DATA段数据未变
CS=0B63H  SS=0B67H  DS=0B66
X+3 X+4
4.
程序3可以正确执行。因为该程序的指令写在前面。程序初始化之后的CS:IP默认指向了指令段的第一句指令。
5.源程序如下:
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       DX,0
              ADD       DL,DS:[BX]
              ADD       DL,ES:[BX]
              MOV       SS:[BX],DL
              INC       BX
              LOOP      s  
             
              MOV       AX,4c00h
              INT       21h
         code ENDS
END       start
6.源代码如下:
ASSUME    CS:code
          a  SEGMENT
              DW        1,2,3,4,5,6,7,8
          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      DS:[BX]
              ADD       BX,2
              LOOP      s
             
              MOV       AX,4c00h
              INT       21h
       code ENDS

END       start
=================================================================
检测点9.1
1 因为jmp word ptr [bx+1] 是段内转移 即:jmp ds:[bx+1] 则需要保证ds:[bx+1]处的2个内存单元数据为data段长度,那么就应该定义data段dd 0,0,3
2 mov [bx],4    (data段长度)
  mov [bx+2],ax (data段段地址)
3 CS=0006 IP=00BE

检测点9.2
1 mov cl,ds:[bx]
  mov ch,0
  jcxz ok
  inc bx

检测点9.3
1 jcxz ok 如果CX读取到00 那么转移条件达成
  或者用inc cx 占用机器码更少,程序更优化。解释:因为前面赋值CL为内存单元数据,CH为0.假设读取到00,那么Inc CX后CX等于0001。当LOOP S执行后(cx)=(cx)-1,这时(cx)=0.所以LOOP S不会执行。

=================================================================
检测点10.1
mov ax,1000h
mov ax,0
=================================================================
检测点11.1
sub 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
            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. jb s0  ;低于32就转移
   ja s0  ;高于128就转移

2. jna s0 ;小于或等于32就转移
   jnb s0 ;大于或等于128就转移

===================================================================
检测点12.1
1.0070:018B

2.N*4   偏移地址
  N*4+2 段地址
====================================================================
检测点13.1
1.add [bp+2],bx   ;因为是由BX决定位移范围,所以是16位位移(16位有符号数范围 -32768 ~ 32767)

检测点13.2
1.不能对FFFF:0000 进行写操作.只能读取.
2.int 19h中断例程不能由DOS提供,因为int 19h是进行操作系统的引导,而DOS就是操作系统,不能由还未加载的程序改变内存,逻辑上错误.

====================================================================
实验13
3. mov dh,ds:[si]     ;ds:si 指向要显示的行号,2.4.6.8
   mov dx,ds:[bx]     ;ds:bx 指向每串字符的偏移地址,因为mov bx,offset s
   inc si
   add,bx,2
====================================================================
检测点14.2
(ax)*10 =(ax)*2+(ax)*8

         mov bx,ax
(ax)*2 = shl ax,1
         mov cl,3
(ax)*8 = shl ax,cl
         add,ax,bx
====================================================================
检测点15.1
1. pushf                  ;绝不可少,因为在中断过程中只有一次标志寄存器入栈,而接下来的
   call dword ptr ds:[0]  ;call有一个iert出栈返回,所以必须多一次入栈,供本程序后面出栈返回

2. cli
   mov word ptr es:[9*4],offset int9
   mov es:[9*4+2],cs
   sti                    ;确保不会被可屏蔽中断干扰
====================================================================
检测点16.1
s: mov ax,a[si]
   add word ptr b,ax
   adc word ptr b[2],0
   add si,2
   loop s

检测点16.2
   mov ax,data
   mov es,ax
======================================================================
检测点17.1

对,在int 16h中断例程中,一定有设置IF=1的指令,因为当CPU引发中断过程时,会将IF置0.然而当键盘缓冲区为空时,int 16h 0号子程序会循环读取键盘缓冲区,直到有数据写入,那么必然需要CPU引发可屏蔽中断的中断过程.所以,必须有设置IF=1的指令

你可能感兴趣的:(王爽汇编 (习题解答))