汇编语言_实验5(超详细)
本帖最后由 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:
push ds:
popds:
popds:
mov ax,4c00h
int 21h
code ends
end start
首先代码输入没什么好说的,就是按着书上抄就行,注意不要打中文格式的字就行(我一开始逗号打成中文了,就报错了)
1.cpu执行程序,程序返回前,data数据段中的数据为多少?
cpu执行程序,程序返回前是哪个阶段,我一直很疑惑,我这里理解成debug 1.exe之后,没有运行程序的任何步骤之前(我的文件命名为1.asm所以编译链接之后就变成了1.exe)
此时用r查看寄存器状态如下:(我才发现我不能上传图片,只能手打,求赞,哭了{:10_319:} )
-R
AX=FFFFBX=0000CX=0042DX=0000SP=0000BP=0000SI=0000DI=0000
DS=075AES=075ASS=0769CS=076CIP=0000NV UP EI PL NZ NA PO NC
076C:0000B86B07 MOV AX,076B
然后用u查看一下汇编语言命令,直接用u查不全,我们根据cs:ip自己查多一部分空间
-U 076c:0 25
076C:0000B86B07 MOV AX,076B
076C:00038ED0 MOV SS,AX
076C:0005BC1000 MOV SP,0010
076C:0008B86A07 MOV AX,076A
076C:000B8ED8 MOV DS,AX
076C:000DFF360000 PUSH
076C:0011FF360200 PUSH
076C:00158F060200 POP
076C:00198F060000 POP
076C:001DB8004C MOV AX,4C00
076C:0020cd21 INT 21
076C:00220000 ADD ,AL
076C:00240000 ADD ,AL
(打完上面一串代码我就在思考,我是谁,我在干嘛了,我要不要试一下开个会员看能不能发图片{:10_247:} )
可以看到在1.asm文件中的data和stack这个两个字段被编译器替换成了076A(data)和076B(stack),感觉类似于c语言中的宏定义。首句assume中定义了data和stack这个两个字段,编译器识别并且赋值,然后替换代码段中所有的data和stack。
好吧,回归题目,此时data数据段中的数据为多少,data是076A,用d查看data段的内容
-d076a:0
076A:0000230156048907BC0A-EF0DED0FBA0C8709 #.V...........'
076A:00100000000000000000-0000000000000000 ................(这个有多少点我也不清楚,乱打的,忽略就好)
(...原谅我打不下去了,用语言描述一下,这一行是076A:0020也就是076C:0000,也就是code段,也就是上面的代码的机器码,我就不多打一遍了,大家自行脑补一下下)
秉着严谨的态度,我用u指令看一下,课本给的数据是不是还可以翻译成指令
-u076A:0
076A:00002301 AND AX,
076A:000256 PUSH SI
076A:00030489 ADD AL,89
076A:000507 POP ES
076A:0006BC0AEF MOV SP,EF0A
076A:00090DED0F OR AX,0FED
076A:000CBA0C87 MOV DX,870C
076A:000F0900 OR ,AX
076A:00110000 ADD ,AX
076A:00130000 ADD ,AX
076A:00150000 ADD ,AX
(自闭ing{:10_293:} )
书本给的数据果然可以翻译成指令,就是,嗯,,看不太懂这些指令想干嘛,不过不重要了,题目又不问这些,有想知道的就自行研究吧。
好,至此,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:0000B86B07 MOV AX,076B
076C:00038ED0 MOV SS,AX ;ss:0769---》076b
076C:0005BC1000 MOV SP,0010
076C:0008B86A07 MOV AX,076A
076C:000B8ED8 MOV DS,AX ;ds:075a---》076a
076C:000DFF360000 PUSH
076C:0011FF360200 PUSH
076C:00158F060200 POP
076C:00198F060000 POP
076C:001DB8004C MOV AX,4C00
076C:0020cd21 INT 21
076C:00220000 ADD ,AL
076C:00240000 ADD ,AL
这里原状态DS=075ASS=0769CS=076c,075A:0-0769:0的15*16个字节是数据段(psp),0769:0-076c:0的3*16个字节是栈段,076c:0之后是代码段
编译器改为DS=076ASS=076bCS=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给字节,如果我猜错了,欢迎大家帮助我改正,嘻嘻{:10_273:} )076C之后是代码段。
好,第一题写完了。(ps:写完第一题的我去看了看怎么升级,毕竟升级就能发图片,不用打字了。然后,我点开了VIP页面,刚刚想买,卧槽,家境贫寒告辞!!{:10_262:} (其实也不算贵,因为教程很棒,但是,无奈我更穷),,,,,,,求精华吧,就想升级不用打字,嘤嘤嘤{:10_327:} )
(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:
push ds:
popds:
popds:
mov ax,4c00h
int 21h
code ends
end start
代码没啥好说的,抄一遍,代码和第一题很像,就删了一点点,不过这个题实在逗我吗,基本上长的一模一样,{:10_285:} 。
1.cpu执行程序,程序返回前,data数据段中的数据为多少?
(由于和第一题相似度过高,第一题我讲的很详细,所以,我就重点写不一样的地方)、
Data被替换为076a,
用r查看寄存器状态发现和第一题一样
-r
AX=FFFFBX=0000CX=0042DX=0000SP=0000BP=0000SI=0000DI=0000
DS=075AES=075ASS=0769CS=076CIP=0000NV UP EI PL NZ NA PO NC
076C:0000B86B07 MOV AX,076B
用-d查看data段的内容
-d076a:0
076A:00002301560400000000-0000000000000000 #.V...........'
076A:00100000000000000000-0000000000000000 ................(一堆数目不明的点)
后面也和第一题一样是code段的指令,我就同样省略了。
data的内容和预估一样,就是前4个字节有
2.cpu执行程序,程序返回前,cs=_____,ss=_______,ds=_______。
由-r的内容,直接填,和第一题的值一样
cs=076C,ss=0769,ds=075A。
3.设程序加载后,code段的段地址是X,则data段的地址为_______,stack段的地址为_________.
代码段和第一题一模一样,还是直接在代码段上写变化
一步一步-t
076C:0000B86B07 MOV AX,076B
076C:00038ED0 MOV SS,AX ;ss:0769---》076b
076C:0005BC1000 MOV SP,0010
076C:0008B86A07 MOV AX,076A
076C:000B8ED8 MOV DS,AX ;ds:075a---》076a
076C:000DFF360000 PUSH
076C:0011FF360200 PUSH
076C:00158F060200 POP
076C:00198F060000 POP
076C:001DB8004C MOV AX,4C00
076C:0020cd21 INT 21
076C:00220000 ADD ,AL
076C:00240000 ADD ,AL
同第一题,ds由075a变成076a,ss由0769变成076b, CS是076C始终不变。那data就是X-2,stack就是X-1
4.对于如下定义的段
name segment
...
nameends
如果段中的数据占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:
push ds:
popds:
popds:
mov ax,4c00h
int 21h
code ends
end start
查看寄存器状态
-r
AX=FFFFBX=0000CX=0052DX=0000SP=0000BP=0000SI=0000DI=0000
DS=075AES=075ASS=0769CS=076DIP=0000NV UP EI PL NZ NA PO NC
076d:0000B86c07 MOV AX,076C
查看汇编指令
-U 076d:0 25
076D:0000B86c07 MOV AX,076C
076D:00038ED0 MOV SS,AX ;ss:0769---》076C
076D:0005BC1000 MOV SP,0010
076D:0008B86A07 MOV AX,076A
076D:000B8ED8 MOV DS,AX ;ds:075a---》076a
076D:000DFF360000 PUSH
076D:0011FF360200 PUSH
076D:00158F060200 POP
076D:00198F060000 POP
076D:001DB8004C MOV AX,4C00
076D:0020cd21 INT 21
076D:00220000 ADD ,AL
076D:00240000 ADD ,AL
这里原状态DS=075ASS=0769CS=076D,075A:0-0769:0的15*16个字节是数据段(psp),0769:0-076D:0的4*16个字节是栈段,076D:0之后是代码段
编译器改为DS=076ASS=076CCS=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:
push ds:
popds:
popds:
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=FFFFBX=0000CX=0044DX=0000SP=0000BP=0000SI=0000DI=0000
DS=075AES=075ASS=0769CS=076aIP=0000NV UP EI PL NZ NA PO NC
076a:0000B86e07 MOV AX,076e
用-d查看data段的内容
-d076d:0
076A:00002301560400000000-0000000000000000 #.V...........'
076A:00100000000000000000-0000000000000000 ................(一堆数目不明的点)
后面都是00
data的内容和预估一样,就是前4个字节有
2.cpu执行程序,程序返回前,cs=_____,ss=_______,ds=_______。
由-r的内容,直接填
cs=076a,ss=0769,ds=075A。
3.设程序加载后,code段的段地址是X,则data段的地址为_______,stack段的地址为_________.
代码段和,还是直接在代码段上写变化
一步一步-t
076a:0000B86e07 MOV AX,076e
076a:00038ED0 MOV SS,AX ;ss:0769---》076b
076a:0005BC1000 MOV SP,0010
076a:0008B86d07 MOV AX,076d
076a:000B8ED8 MOV DS,AX ;ds:075a---》076a
076a:000DFF360000 PUSH
076a:0011FF360200 PUSH
076a:00158F060200 POP
076a:00198F060000 POP
076a:001DB8004C MOV AX,4C00
076a:0020cd21 INT 21
076a:00220000 ADD ,AL
076a:00240000 ADD ,AL
这里原状态DS=075ASS=0769CS=076a,075A:0-0769:0的15*16个字节是数据段(psp),0769:0-076a:0的16个字节是栈段,076a之后是代码段,
编译器改为DS=076dSS=076eCS=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:
mov ,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:
add ,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 ;将a段前8个数据入栈
add bx,2 ;字型数据加2,两个inc是4个十六进制的代码,而add是3个,所以用add,省空间
loop s
mov ax,4c00h
int 21h
code ends
end start
经检验,答案正确
欢迎留言交流 前面三道题你的理解有误 程序返回前指的是 debug -t单步运行到下一步执行 int 这一步。。运行了int就是返回了N个字节占有空间应该是 16X( N/16 +1 ) 最后一问,你只push入栈 逆序排列你没写 狂热终结者 发表于 2021-3-30 15:21
最后一问,你只push入栈 逆序排列你没写
这个东西,我当时想的是,因为出栈就是逆序的,就没反着入栈,可能当时理解错了。{:10_262:} 5.5 其实用一次循环就可以解决,并且a & b端数据重复了,可以double a的 谢谢楼主,楼主辛苦了,在下佩服,不给截图着实可恶。 good !!!{:10_249:} 第五题确实坑爹, c不行,改成其他的才行
页:
[1]