|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 635924705 于 2021-2-5 22:53 编辑
【手打不宜,错了勿喷,还请斧正,万分感谢,学习交流,共同进步】
【文中大部分数字都是16进制,我没加h,希望不影响大家阅读】
【文中个别不重要的机器码可能错了几个地方,因为有复制前面的,作者自查了一遍,还是可能有遗漏,我下次一定要发图片】
(1)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
首先代码输入没什么好说的,就是按着书上抄就行,注意不要打中文格式的字就行(我一开始逗号打成中文了,就报错了)
1.cpu执行程序,程序返回前,data数据段中的数据为多少?
cpu执行程序,程序返回前是哪个阶段,我一直很疑惑,我这里理解成debug 1.exe之后,没有运行程序的任何步骤之前(我的文件命名为1.asm所以编译链接之后就变成了1.exe)
此时用r查看寄存器状态如下:(我才发现我不能上传图片,只能手打,求赞,哭了 )
-R
AX=FFFF BX=0000 CX=0042 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=075A ES=075A SS=0769 CS=076C IP=0000 NV UP EI PL NZ NA PO NC
076C:0000 B86B07 MOV AX,076B
然后用u查看一下汇编语言命令,直接用u查不全,我们根据cs:ip自己查多一部分空间
-U 076c:0 25
076C:0000 B86B07 MOV AX,076B
076C:0003 8ED0 MOV SS,AX
076C:0005 BC1000 MOV SP,0010
076C:0008 B86A07 MOV AX,076A
076C:000B 8ED8 MOV DS,AX
076C:000D FF360000 PUSH [0000]
076C:0011 FF360200 PUSH [0002]
076C:0015 8F060200 POP [0002]
076C:0019 8F060000 POP [0000]
076C:001D B8004C MOV AX,4C00
076C:0020 cd21 INT 21
076C:0022 0000 ADD [BX+SI],AL
076C:0024 0000 ADD [BX+SI],AL
(打完上面一串代码我就在思考,我是谁,我在干嘛了,我要不要试一下开个会员看能不能发图片 )
可以看到在1.asm文件中的data和stack这个两个字段被编译器替换成了076A(data)和076B(stack),感觉类似于c语言中的宏定义。首句assume中定义了data和stack这个两个字段,编译器识别并且赋值,然后替换代码段中所有的data和stack。
好吧,回归题目,此时data数据段中的数据为多少,data是076A,用d查看data段的内容
-d 076a:0
076A:0000 23 01 56 04 89 07 BC 0A-EF 0D ED 0F BA 0C 87 09 #.V...........'
076A:0010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................(这个有多少点我也不清楚,乱打的,忽略就好)
(...原谅我打不下去了,用语言描述一下,这一行是076A:0020也就是076C:0000,也就是code段,也就是上面的代码的机器码,我就不多打一遍了,大家自行脑补一下下)
秉着严谨的态度,我用u指令看一下,课本给的数据是不是还可以翻译成指令
-u 076A:0
076A:0000 2301 AND AX,[BX+DI]
076A:0002 56 PUSH SI
076A:0003 0489 ADD AL,89
076A:0005 07 POP ES
076A:0006 BC0AEF MOV SP,EF0A
076A:0009 0DED0F OR AX,0FED
076A:000C BA0C87 MOV DX,870C
076A:000F 0900 OR [BX+SI],AX
076A:0011 0000 ADD [BX+SI],AX
076A:0013 0000 ADD [BX+SI],AX
076A:0015 0000 ADD [BX+SI],AX
(自闭ing )
书本给的数据果然可以翻译成指令,就是,嗯,,看不太懂这些指令想干嘛,不过不重要了,题目又不问这些,有想知道的就自行研究吧。
好,至此,data的内容和data段的内容我们都得出来了,应该是完成了第一问。
2.cpu执行程序,程序返回前,cs=_____,ss=_______,ds=_______。
嗯,就是抄寄存器状态呗,见第一问-r查看的内容。
cs=076C,ss=0769,ds=075A。
在这里我们可以看到,这个程序默认的开头是数据段(psp),在075a,之后是栈段,栈的底层在0769,最后是代码段,在076c。
psp一共256个字节,低位是psp的开头指令(int 20啥的,感兴趣的可以自己看),最高位是栈的起始地址(栈是由高位向低位存储),个人感觉不安全,要是我栈段存300给字节,PSP的内容就会被覆盖掉。
3.设程序加载后,code段的段地址是X,则data段的地址为_______,stack段的地址为_________.
题目问的是真的模糊,如果问的是data和stack的值,那程序加载后,其实已经过了编译器data和stack就不存在了,debug里面可没有data和stack,只有被替换出来的值,如第一问,076A(data)和076B(stack)。那我权当她问的是ds和ss这两个段寄存器的段地址吧。
那就一步一步-t。(全抄太麻烦,我在汇编指令旁边标上ds和ss会变化的地方)
076C:0000 B86B07 MOV AX,076B
076C:0003 8ED0 MOV SS,AX ;ss:0769---》076b
076C:0005 BC1000 MOV SP,0010
076C:0008 B86A07 MOV AX,076A
076C:000B 8ED8 MOV DS,AX ;ds:075a---》076a
076C:000D FF360000 PUSH [0000]
076C:0011 FF360200 PUSH [0002]
076C:0015 8F060200 POP [0002]
076C:0019 8F060000 POP [0000]
076C:001D B8004C MOV AX,4C00
076C:0020 cd21 INT 21
076C:0022 0000 ADD [BX+SI],AL
076C:0024 0000 ADD [BX+SI],AL
这里原状态DS=075A SS=0769 CS=076c,075A:0-0769:0的15*16个字节是数据段(psp),0769:0-076c:0的3*16个字节是栈段,076c:0之后是代码段
编译器改为DS=076A SS=076b CS=076c,075A:0-076A:0的16*16个字节是psp,076A:0-076b:0的1*16个字节是数据段,076b:0-076c:0的1*16个字节是栈段,076c:0之后是代码段
(个人猜测,因为编译器不知道你要个什么段,所以,我们每声明一个段,编译器就自动给个n*16个字节的空间。因为这几个段我们存的数据都少于16个字节,所以统一为16给字节,如果我猜错了,欢迎大家帮助我改正,嘻嘻 )076C之后是代码段。
好,第一题写完了。(ps:写完第一题的我去看了看怎么升级,毕竟升级就能发图片,不用打字了。然后,我点开了VIP页面,刚刚想买,卧槽,家境贫寒告辞!! (其实也不算贵,因为教程很棒,但是,无奈我更穷),,,,,,,求精华吧,就想升级不用打字,嘤嘤嘤 )
(2)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数据段中的数据为多少?
(由于和第一题相似度过高,第一题我讲的很详细,所以,我就重点写不一样的地方)、
Data被替换为076a,
用r查看寄存器状态发现和第一题一样
-r
AX=FFFF BX=0000 CX=0042 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=075A ES=075A SS=0769 CS=076C IP=0000 NV UP EI PL NZ NA PO NC
076C:0000 B86B07 MOV AX,076B
用-d查看data段的内容
-d 076a:0
076A:0000 23 01 56 04 00 00 00 00-00 00 00 00 00 00 00 00 #.V...........'
076A:0010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................(一堆数目不明的点)
后面也和第一题一样是code段的指令,我就同样省略了。
data的内容和预估一样,就是前4个字节有
2.cpu执行程序,程序返回前,cs=_____,ss=_______,ds=_______。
由-r的内容,直接填,和第一题的值一样
cs=076C,ss=0769,ds=075A。
3.设程序加载后,code段的段地址是X,则data段的地址为_______,stack段的地址为_________.
代码段和第一题一模一样,还是直接在代码段上写变化
一步一步-t
076C:0000 B86B07 MOV AX,076B
076C:0003 8ED0 MOV SS,AX ;ss:0769---》076b
076C:0005 BC1000 MOV SP,0010
076C:0008 B86A07 MOV AX,076A
076C:000B 8ED8 MOV DS,AX ;ds:075a---》076a
076C:000D FF360000 PUSH [0000]
076C:0011 FF360200 PUSH [0002]
076C:0015 8F060200 POP [0002]
076C:0019 8F060000 POP [0000]
076C:001D B8004C MOV AX,4C00
076C:0020 cd21 INT 21
076C:0022 0000 ADD [BX+SI],AL
076C:0024 0000 ADD [BX+SI],AL
同第一题,ds由075a变成076a,ss由0769变成076b, CS是076C始终不变。那data就是X-2,stack就是X-1
4.对于如下定义的段
name segment
...
name ends
如果段中的数据占n个字节,则程序加载后,该段实际占有的空间为______.
(终于有一题不一样了)
这一问的问题,我们在第一题就有过猜想,就是n*16个字节,现在已经验证了16,10,4,2个字节都是16个字节的空间,所以,我们来一个20给字节的声明,看一下编译器给多少空间就知道,我们的猜想对不对了。
懒惰的我,就不改段名字了,直接在data段做实验。assume cs:code, ds:data, ss:stack
data segment
dw 0123h,0456h,0123h,0456h,0123h,0456h,0123h,0456h,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
查看寄存器状态
-r
AX=FFFF BX=0000 CX=0052 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=075A ES=075A SS=0769 CS=076D IP=0000 NV UP EI PL NZ NA PO NC
076d:0000 B86c07 MOV AX,076C
查看汇编指令
-U 076d:0 25
076D:0000 B86c07 MOV AX,076C
076D:0003 8ED0 MOV SS,AX ;ss:0769---》076C
076D:0005 BC1000 MOV SP,0010
076D:0008 B86A07 MOV AX,076A
076D:000B 8ED8 MOV DS,AX ;ds:075a---》076a
076D:000D FF360000 PUSH [0000]
076D:0011 FF360200 PUSH [0002]
076D:0015 8F060200 POP [0002]
076D:0019 8F060000 POP [0000]
076D:001D B8004C MOV AX,4C00
076D:0020 cd21 INT 21
076D:0022 0000 ADD [BX+SI],AL
076D:0024 0000 ADD [BX+SI],AL
这里原状态DS=075A SS=0769 CS=076D,075A:0-0769:0的15*16个字节是数据段(psp),0769:0-076D:0的4*16个字节是栈段,076D:0之后是代码段
编译器改为DS=076A SS=076C CS=076D,075A:0-076A:0的16*16个字节是psp,076A:0-076C:0的2*16个字节是数据段,076C:0-076D:0的1*16个字节是栈段,076D:0之后是代码段
验证,我们的猜想应该是对的,debug,会把ds指向psp开始,ss指向psp的15*16个字节之后,小甲鱼老师说psp是16*16个字节,所以初始状态,PSP末尾的16个字节是栈段的。PSP和代码段中间有n*16个字节。n的值是每一段的数据的个数除以16然后向上取整,最后求和。编译器的话,会保护psp,将psp的16*16个字节保护,ds指向PSP之后,ss指向ds之后,根据其数据的个数,划分n*16个字节的空间)
(3)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
代码直接抄,没啥好说的,题目还是一样的,我仿佛知道这个题目是什么意思了,就是想让我们知道编译器和debug的运转
1.cpu执行程序,程序返回前,data数据段中的数据为多少?
Data被替换为076d,
用r查看寄存器
-r
AX=FFFF BX=0000 CX=0044 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=075A ES=075A SS=0769 CS=076a IP=0000 NV UP EI PL NZ NA PO NC
076a:0000 B86e07 MOV AX,076e
用-d查看data段的内容
-d 076d:0
076A:0000 23 01 56 04 00 00 00 00-00 00 00 00 00 00 00 00 #.V...........'
076A:0010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................(一堆数目不明的点)
后面都是00
data的内容和预估一样,就是前4个字节有
2.cpu执行程序,程序返回前,cs=_____,ss=_______,ds=_______。
由-r的内容,直接填
cs=076a,ss=0769,ds=075A。
3.设程序加载后,code段的段地址是X,则data段的地址为_______,stack段的地址为_________.
代码段和,还是直接在代码段上写变化
一步一步-t
076a:0000 B86e07 MOV AX,076e
076a:0003 8ED0 MOV SS,AX ;ss:0769---》076b
076a:0005 BC1000 MOV SP,0010
076a:0008 B86d07 MOV AX,076d
076a:000B 8ED8 MOV DS,AX ;ds:075a---》076a
076a:000D FF360000 PUSH [0000]
076a:0011 FF360200 PUSH [0002]
076a:0015 8F060200 POP [0002]
076a:0019 8F060000 POP [0000]
076a:001D B8004C MOV AX,4C00
076a:0020 cd21 INT 21
076a:0022 0000 ADD [BX+SI],AL
076a:0024 0000 ADD [BX+SI],AL
这里原状态DS=075A SS=0769 CS=076a,075A:0-0769:0的15*16个字节是数据段(psp),0769:0-076a:0的16个字节是栈段,076a之后是代码段,
编译器改为DS=076d SS=076e CS=076a,075A:0-0769:0的16*16个字节是psp,076A:0-076d:0的3*16个字节是代码段,076d:0-076e:0的1*16个字节是数据段,076e:0之后是栈段
由此,我们可以看出来,段的顺序和我们编程的顺序是一样的,因为此题的栈段和数据段的编程在后面,所以,psp和代码段中间只有16个字节的初始的栈段。
联想到编译和链接文件时,会警告没有栈段,所以,我感觉没有栈段的时候,ss才会指向psp的后16位
得出,data段的地址为x+3,stack段的地址为x+4。
(4)
不声明代码段入口的话,只有(3)的程序能正常运行,因为(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
d segment ;我用c做段名就报错,无奈,我改成了d,求大佬帮我解答why
db 0,0,0,0,0,0,0,0
d ends
code segment
start:
mov ax,d
mov ds,ax ;将d的段地址给ds
mov ax,a
mov es,ax ;将a的段地址给es
mov bx,0
mov cx,8
s1: mov al,es:[bx]
mov [bx],al ;将a段的值给d段,不用中转al会报错,不能用ax因为ax是2个字节,每个地址只有一个字节,可能出现未知错误
inc bl
loop s1
mov ax,b
mov es,ax ;将b的段地址给es
mov bx,0
mov cx,8
s2: mov al,es:[bx]
add [bx],al ;将b段的值加给d段
inc bl
loop s2
mov ax,4c00h
int 21h
code ends
end start
经检验,答案正确
(6)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,b ;把b段视为栈空间
mov ss,ax
mov sp,10h ;直接给b段的末尾地址给sp
mov ax,a
mov ds,ax ;将a段的地址给ds
mov bx,0
mov cx,8
s: push [bx] ;将a段前8个数据入栈
add bx,2 ;字型数据加2,两个inc是4个十六进制的代码,而add是3个,所以用add,省空间
loop s
mov ax,4c00h
int 21h
code ends
end start
经检验,答案正确
[u]欢迎留言交流[/u] |
|