王爽 汇编语言个人疑问汇总第二篇(5-6章)
第五章
实验4 [bx]和loop的使用
- (1)编程,向内存0:200 ~ 0:23F依次传送数据0 ~ 63(3FH)。
- (2)编程,向内存0:200 ~ 0:23F依次传送数据0 ~ 63(3FH),程序中只能使用9条指令,9条指令包括 “mov ax,4c00h”和“int 21h”
- (1)和(2)的代码
assume cs:code
code segment
mov ax,020H ; (ax)=020H
mov ds,ax ; (ds)=020H
mov bx,0 ; 初始化bx,(bx)=0
mov cx,63 ; (cx)=63 ,表示循环63次
s:mov [bx],bx ; ((ds) * 10H + (bx)) = (bx) , 将bx中的数据送入020H:bx中
inc bx ; (bx) = (bx) + 1
loop s ; 循环
mov ax,4c00H ; 固定的结束代码
int 21H ; 固定的结束代码
code ends
end
- (3)下面的程序的功能是将"mov ax,4c00h"之前的指令复制到内容0:200处,补全程序。上机调试,跟踪运行结果。
什么叫做 mov ax,4c00H 之前的指令 ?
指令也是数据,CS:IP 指向的就是指令,因此,mov ax,_____ 这里必然是填上 CS 的,也就是 mov ax,cs
寄存器 CX 控制的是循环次数,那么 mov cx,____ 这里必然要填上一个数字,代表循环次数
程序的功能是复制一系列指令,那么cx寄存器后面需要填上的数字必然与这一系列指令的个数相关
mov ax,cs
确定了,mov cx,____
未确定,我随便写了个11,编译后debug,结果如下图。
mov ax,4C00h
的起始地址是0017H
,直接与第一条指令的0000H
相减,马上就可以得到17H
。- 完整代码
assume cs:code
code segment
mov ax,cs ;需要把ds数据段指向指令段
mov ds,ax
mov ax,0020h
mov es,ax
mov bx,0
mov cx,17H ;通过debug -u命令可以查看
;mov ax,4c00h 的IP为 0017h
;也就是程序长度17h
s:mov al,[bx]
mov es:[bx],al
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end
参考大佬的文章: [023][汇编语言]实验4 [bx]和loop的使用(复制指令)
第六章
检测点6.1
(1)下面的程序实现依次用内存0:0~0:15单元中的内容改写程序中的数据,完成程序:
assume cs:codesg
codesg segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
start: mov ax,0
mov ds,ax ;初始化数据段地址指向段地址0的位置
mov bx,0
mov cx,8 ;寄存器是16位结构的,刚好8个字型数据所以循环8次
s: mov ax,[bx]
;----------------------------------------------------------------
mov cs:[bx],ax ; 程序启动cs自动定位到程序的地址,所以修改cs段寄存器就好了
;-----------------------------------------------------------------
add bx,2 ;一个字型数据占两个内存单元,每次偏移2
loop s
mov ax,4c00h
int 21h
codesg ends
end start
(2)下面的程序实现依次用内存0:0~0:15单元中的内容改写程序中的数据,数据的传送用栈来进行。栈空间设置在程序内。完成程序:
- 这里要注意下1个字型数据等于2个字节;
- 第一个dw关键词开辟了8个字的空间,并且存入了数据
- 第二个dw关键词开辟了10个字的空间,用作栈空间
- 可以计算出栈顶的偏移地址 SP = (8+10)x2= 36 =24H ;十六进制为24H,十进制为36。
assume cs:codesg
codesg segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h ;定义数据
dw 0,0,0,0,0,0,0,0,0,0 ; 10个字单元用作栈空间
-------------------------------------
start: mov ax,cs ; 定义代码段
-------------------------------------
mov ss,ax ; 定义栈段
-------------------------------------
mov sp,24H ; 定义栈底为36 (8*2 + 10*2)
-------------------------------------
mov ax,0
mov ds,ax ; 定义内存起始段
mov bx,0 ; 定义内存偏移
mov cx,8 ; 定义循环次数
s: push [bx] ; 将ds:[bx]内存单元中的数据写入栈单元ss:sp(sp=24h) -> sp=24h - 2h = 22h
-------------------------------------
pop cs:[bx] ; 将ss:sp(sp=22h)为栈顶的字单元中的数据写入cs:[bx]中 -> sp=22h + 2h = 24h
--------------------------------------
add bx,2 ; 相邻两个字节单元为一个字单元,因此偏移2
loop s
mov ax,4c00h
int 21h
codesg ends
end start
参考大佬的文章 [024][汇编语言]检测点6.1 在同一个代码段里使用数据和栈
实验5
(1)将下面的程序编译连接,用Debug加载、跟踪,然后回答问题
assume cs:code,ds:data,ss:stack
data segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
data ends
stack segment
dw 0,0,0,0,0,0,0,0
stack ends
code segment
start:
mov ax,stack
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
push ds:[0]
push ds:[2]
pop ds:[2]
pop ds:[0]
mov ax,4c00h
int 21h
code ends
end start
- debug运行,如下图所示。
注意:所有DS与源程序代码之间的段地址都是相差10h,。最开始DS的值为075A,则PSP的地址为075AH:0,程序的地址为076AH:0(075AH+10H)
- (1)CPU执行程序,程序返回前,data段中的数据为多少?
0123H, 0456H, 0789H, 0abcH, 0defH, 0fedH, 0cbaH, 0987H
- (2)CPU执行程序,程序返回前,cs=,ss=,ds=_。
由上图可知道,在执行int 12h
之前:
CS = 076C
SS = 076B
DS = 076A
- (3)设程序加载后,code段的段地址为X,则data段的段地址为_,stack段的段地址为_。
code(代码)段是指向CS,data(数据)段指向DS,stack(栈)段指向SS。从第(2)题答案我们已经知道CS 、SS 、DS ,可以观察出其中规律,相邻之间相差1H。
所以:
data段地址为 X - 2H
stack段地址为 X - 1H
(2)将下面的程序编译、连接,用Debug加载、跟踪,然后回答问题
assume cs:code,ds:data,ss:stack
data segment
dw 0123h,0456h
data ends
stack segment
dw 0,0
stack ends
code segment
start:
mov ax,stack
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
push ds:[0]
push ds:[2]
pop ds:[2]
pop ds:[0]
mov ax,4c00h
int 21h
code ends
end start
- (1)CPU执行程序,程序返回前,data段中的数据为多少?
0123H, 0456H, 0,0,0,0,0,0
- (2)CPU执行程序,程序返回前,cs=,ss=,ds=_。
由上图可知道,在执行int 12h
之前:
CS = 076C
SS = 076B
DS = 076A
- (3)设程序加载后,code段的段地址为X,则data段的段地址为_,stack段的段地址为_。
code(代码)段是指向CS,data(数据)段指向DS,stack(栈)段指向SS。从第(2)题答案我们已经知道CS 、SS 、DS ,可以观察出其中规律,相邻之间相差1H。
所以:
data段地址为 X - 2H
stack段地址为 X - 1H
- (4)对于如下定义的段:
name segment
…
name ends
如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为_。
如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为: 16 * [(N-1)/16 + 1],此处实际字节数是4
N/16:取整
即使name段中只包含一个字节,也要占一个段(16个字节)。参考汇编 | 段中的实际数据大小与占用空间大小问题
(3)将下面的程序编译、连接,用Debug加载、跟踪,然后回答问题。
assume cs:code,ds:data,ss:stack
code segment
start:
mov ax,stack
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
push ds:[0]
push ds:[2]
pop ds:[2]
pop ds:[0]
mov ax,4c00h
int 21h
code ends
data segment
dw 0123h,0456h
data ends
stack segment
dw 0,0
stack ends
end start
- CPU执行程序,程序返回前,data段中的数据为多少?
0123H, 0456H, 0,0,0,0,0,0
- CPU 执行程序,程序返回前
CS = 076AH,SS = 076EH,DS = 076DH
- 设程序加载后,code段的段地址为X
则data段的段地址为 X + 3, stack段的段地址为 X + 4
(4)如果将(1)、(2)、(3)题中的最后一条伪指令"end start"改为"end"(也就是不说明程序的入口),则哪个程序仍然可以正确执行?为什么?
实验中(3)的程序可以正确执行,如果程序的位置发生了变化,并且将程序入口标识start去掉,程序就会从上往下执行
(5)编写code段中的代码,将a段和b段中的数据依次相加,将结果你存到c段中
- 原程序
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:
?
code ends
end start
- 修改后
assume并不需要声明a、b、c;操作的是字节,inc bx累加1即可。
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 ; 先把a段=ds段寄存器
mov ax,c
mov es,ax ; c段=es段寄存器
mov cx,8 ; 复制8个单字节,循环8次即可
mov bx,0 ; bx清零
s:
mov ah,0 ; 因为是单字节所以ax寄存器高位不需要,置为0即可
mov al,ds:[bx] ; ax的低位al = ds:[bx]
mov es:[bx],al ;mov es:[bx],ax也可以
inc bx ;单字节,自增1
loop s ; 循环
mov cx,8
mov bx,0
mov ax,b
mov ds,ax ; 把b=ds段寄存器
s0:
mov ah,0 ; 不需要高位,置为0
mov al,ds:[bx] ; 低位al = ds:[bx]
add es:[bx],al ; es:[bx]相当于取的是a数据段的值 al (ds:[bx])是b数据段的值,两者累加
inc bx ; 加1
loop s0 ; 循环
mov ax,4c00h
int 21h
code ends
end start
- 执行结果
(6)程序如下,编写code段中的代码,用push指令将a段中的前8个字型数据,逆序存储到b段中
- 原程序
assume cs:code
a segment
dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh,0fh,0ffh ;16字,32字节
a ends
b segment
dw 0,0,0,0,0,0,0,0
b ends
code segment
start:
?
code ends
end start
- 修改后
本题操作是是字,占用2个字节,所以循环累加2。
逆序,结合前面的知识栈有这个特性。
assume cs:code
a segment
dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh,0fh,0ffh ;16字,32字节
a ends
b segment
dw 0,0,0,0,0,0,0,0
b ends
code segment
start:
mov ax,a
mov ds,ax ; 希望用ds:bx访问a段的数据,ds指向a段
mov ax,b
mov ss,ax
mov sp,16 ; 希望b作为栈空间,设置ss:sp指向b:16
mov bx,0 ;段地址偏移字节数
mov cx,16 ;循环次数
s:
push [bx] ; 意为 ds:[bx] ,把数据放入栈中
add bx,2 ;字型数据占两个字节 ,或者 inc bx inc bx 累加 2次
loop s ; 循环
mov ax,4c00h
int 21h
code ends
end start
- 结果