王爽 汇编语言个人疑问汇总1-3章

第一章 基础知识

  • 1个CPU的寻址能力为8KB,那么它的地址总线的宽度为?

8KB=8*1024=8192Byte
8192Byte = 2^13Byte
这样的CPU最多可以寻址2的13次方个内存单元
所以总线宽度为13

第二章 寄存器

  • 16位寄存器为什么只能存放4位十六进制?

16位是16个二进制位,1个16进制数得用 4个二进制数才能表示,4位16进制刚好满16二进制位。

  • 关于十六进制的计算,8226H + 8226H计算过程。需要对照下图表格。

在这里插入图片描述

8226H+8226H=?;
6 + 6 = 12 十六进制中用C表示
2 + 2 = 4 十六进制中也用4表示
8 + 8 = 16 十六进制用10表示
那么完整结果就是1044CH
又因为只能存4位16进制,所以溢出,1就显示不了了,最后结果044CH

问题2.2

  • …省略… add al,93H
  • 指令执行后AX中的数据为多少?

al是C5H ,那就是 al = C5H + 93H
5 + 3 = 8
C + 9 = 12 + 9 =21
因为十六进制满16进位1,所以前面进位1,还剩下5.
结果是158H
因为al是8位存储器,只能存2位16进制数据。
所以最高位1丢失,最终结果58H,ax中的数据为0058H

由段地址 * 16引发的讨论

在这里插入图片描述

  • 观察上图就可得出规律:
    (1) 一个数据的二进制形式左移1位,相当于该数据乘以2;
    (2)一个数据的二进制形式左移N位,相当于该数据乘以2的N次方;
    (3)地址加法器如何完成段地址*16(16换成十六进制是10H)的运算呢?以二进制形式存放的段地址左移4位(看最后一个)。
    进一步思考:一个数据的十进制左移一位,相当于乘以10(十进制的10);一个数据的十六进制左移一位,相当于乘以16(十进制的16);一个数据的X进制左移一位,相当于乘以X。

检测点2.2

  • 给定段地址为0001H,仅通过变化偏移地址寻址,CPU的寻址范围为?

SA * 16 + EA = 物理地址
EA的变化范围为0H~FFFFH
物理地址范围为 (SA16+0H)~(SA16+FFFFH)
现在SA=0001H,代入得:
(0001H * 16+0H)~(0001H * 16+FFFFH) = 00010H ~ 1000F

  • 有一数据存放在内存20000H单元中,现给定段地址为SA,若想用偏移地址寻址到此单元,则SA 应满足的条件是?

已知公式是这样的 SA * 16 + EA = 物理地址
EA的变化范围为0H~FFFFH
代入下 SA * 16 + EA = 20000H ; 注意这个16换成十六进制就是10H
现在求SA(段地址)的最大值 SA = (20000H - 0H) / 10H
所以最大值为2000H
求SA(段地址)的最小值 SA = (20000H - FFFFH) / 10H = 1000.1H
答案是1000.1H,不满足16的倍数,方程不成立。FFFF是最大,不能再大了,所以只能减小。直到… (要直到除以16是整数为止)
最后使用FFF0H ;SA = (20000H - FFF0H) / 16=10010H / 16 = 1001H
注意段地址小于1001H,或者大于2000H都无法得到物理地址20000H

检测点2.3

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

mov ax,bx
sub ax,ax
jmp ax

先说结论:修改了4次IP,最后IP为0。
第1次:从存储器中读取mov ax, bx指令之后,IP立即改变,指向下一条指令(sub ax, ax)的地址。
第2次:从存储器读取sub ax, ax之后(在此之前,会先执行mov ax, bx指令),IP立即改变,指向下一条指令(jmp ax)的地址。
第3次:从存储器读取jmp ax指令之后(在此之前,会先执行完sub ax, ax指令),IP立即改变,指向下一条指令的地址,这里由于下一条指令没有标明,所以不知道,反正此时IP的值是紧挨jmp ax之后的地址。
第4次:执行jmp ax指令后。jmp指令是通过修改IP的值来达到使程序执行跳转的目的的,因此执行jmp之后,IP的值变为ax(此时值为0)的值,所以修改为了0。
为什么最后等于0? 因为sub ax,ax,减去了自身,所以ax = 0。

检测点3.1

  • (1) 在DEBUG中,用 "d 0:0 lf" 查看内存,结果如下(自己的结果可能不是这个,可以用e命令写入):

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,写出每条汇编指令执行完后相关寄存器中的值

mov ax,1
mov ds,ax ;DS=AX=0001H,是段寄存器指向0001:0,ds:[0000]的物理地址为00010H(即物理地址=0001*16+0000=00010H)
mov ax,[0000] AX=2662H ;ax=ds:[0000]=2262H
mov bx,[0001] BX=E626H
mov ax,bx AX=E626H
mov ax,[0000] AX=2662H
mov bx,[0002] BX=D6E6H
add ax,bx AX=FD48H
add ax,[0004] AX=2C14H ;AX=12C14H,溢出舍去最高位1
mov ax,0 AX=0
mov al,[0002] AX=00E6H
mov bx,0 BX=0
mov bl,[000c] BX=0026H
add al,bl AX=000CH ; al + bl = 10C ,al是8位寄存器,只能存储2个十六进制数,溢出舍去1得0C

关于为什么取 0000:0010,借用下高人的回复 “你看啊,ds中的值是1,偏移地址是0,而物理地址=段地址*16+偏移地址,也就是说不同的段地址和偏移地址的组合可以指向同一个内存单元,这个你明白吧,那么0001:0000的组合就相当于0000:0010,将此位置的字型数据送入寄存器AX,高地址内存单元存放字型数据的高位字节,低地址内存单元存放字型数据的低位字节,也就是2662H”

  • 内存中的情况如图3.6所示;各寄存器的初始值:cs=2000h,ip=0,ds=1000h,ax=0,bx=0;
    在这里插入图片描述
  • 解析

【1】CPU总是从cs:ip指向的内存单元读取指令并运行。故先从mov ax,6622H读取并执行。
cs=2000H;ip=0003H; ds=1000H ;ax=6622H;bx=0000H

【2】执行jmp指令(段间直接跳转),确定0ff0:0100的物理地址是:0ff0*10H+100H=10000H;故CPU从物理地址是10000H开始处读取并执行代码。正好在10000H单元开始有指令:mov ax,2000H。这也证明了物理地址是唯一的,基础地址+偏移地址的组合是多种的。
cs=0ff0H;ip=0103H;ds=1000H;ax=2000H;bx=0000H

【3】开始执行下一个指令:mov ds,ax;
cs=0ff0H;ip=0105H;ds=2000H;ax=2000H;bx=0000H

【4】执行下一个指令:mov ax,[0008],由于ds指向了2000H段内存,[0008]代表了字型单元,值为C389H
cs=0ff0H;ip=0108H;ds=2000H;ax=C389H;bx=0000H

【5】执行下一个指令:mov ax,[0002],由于ds指向了2000H段内存,[0002]代表了字型单元,值为EA66H
cs=0ff0H;ip=010BH;ds=2000H;ax= EA66H;bx=0000H

  • 答案
    • CPU执行序列为

      mov ax,6622H
      jmp 0ff0:0100
      mov ax,2000H
      mov ds,ax
      mov ax,[0008]
      mov ax,[0002]

      • CPU执行每条指令后,cs、ip和相关寄存器的值:

      mov 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

再次体会,数据和指令(数据和程序)在内存中存储是没有区别的,是数据还是指令?
需要看它具体的应用体现。如果CS:IP指向的内存单元,那么它就作为CPU指令读取并执行。

检测点3.2

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

在这里插入图片描述

mov ax,1000H

mov ds,ax

——
——
——

push [0]

push [2]

push [4]

push [6]

push [8]

push [A]

push [C]

push [E]

解析:
中间留下3条指令由我们补全。
push是将右边内存单元的存入栈中,这里的内存单元就是10000H ~ 1000FH这段,那么这个栈我们指向20000H~2000FH就可以达成目标了,依据前面学过的知识,我们只需要改变SS:SP指向就可以了。SS = 2000H;如果有一条数据是 SP = 000EH;空栈 那么还要 + 2H SP = 0010H。
完整代码 :

mov ax,1000H
mov ds,ax
mov ax,2000H ;由于ss是段寄存器,必须间接赋值。
mov ss,ax ;使ss栈顶指向2000H段内存
mov sp,10H ;初始化栈顶指针,栈空状态,向低地址发展
push [0]
push [2]
push [4]
push [6]
push [8]
push [A]
push [C]
push [E]

(2)补全下面的程序,使其可以将10000H-1000FH中的8个字,逆序拷贝到20000H-2000FH中。 程序分析:这个程序是通过pop指令在内存中复制数据的。同上述基本差不多。

mov ax,2000H
mov ds,ax
mov ax,1000H
——————
mov ss,ax ;使ss栈顶指向1000H段内存
——————
mov sp,0 ;初始化栈顶指针,由于栈结构满了,sp=0,向高地址发展,保证逆序
——————
pop [e] ; pop 从栈中取出,赋值给[e]内存单元,每次pop后, SP = SP+ 2H
pop [c]
pop [a]
pop [8]
pop [6]
pop [4]
pop [2]
pop [0]

posted on 2021-09-14 09:36  愤怒的苹果ext  阅读(214)  评论(0编辑  收藏  举报

导航