鱼C论坛

 找回密码
 立即注册
查看: 6713|回复: 7

[汇编作业] 汇编语言_实验5(超详细)

[复制链接]
发表于 2021-2-5 22:53:37 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 635924705 于 2021-2-5 22:53 编辑

【手打不宜,错了勿喷,还请斧正,万分感谢,学习交流,共同进步】
【文中大部分数字都是16进制,我没加h,希望不影响大家阅读】
【文中个别不重要的机器码可能错了几个地方,因为有复制前面的,作者自查了一遍,还是可能有遗漏,我下次一定要发图片】
(1)
  1. assume cs:code, ds:data, ss:stack

  2. data segment
  3.     dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
  4. data ends

  5. stack segment
  6.     dw 0,0,0,0,0,0,0,0
  7. stack ends

  8. code segment
  9. start:  mov ax,stack
  10.         mov ss,ax
  11.         mov sp,16       
  12.         mov ax,data
  13.         mov ds,ax
  14.         push ds:[0]
  15.         push ds:[2]
  16.         pop  ds:[2]
  17.         pop  ds:[0]               
  18.        
  19.         mov ax,4c00h
  20.         int 21h
  21.        
  22. code ends

  23. 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)
  1. assume cs:code, ds:data, ss:stack

  2. data segment
  3.     dw 0123h,0456h
  4. data ends

  5. stack segment
  6.     dw 0,0
  7. stack ends

  8. code segment
  9. start:  mov ax,stack
  10.         mov ss,ax
  11.         mov sp,16
  12.         mov ax,data
  13.         mov ds,ax
  14.         push ds:[0]
  15.         push ds:[2]
  16.         pop  ds:[2]
  17.         pop  ds:[0]               
  18.        
  19.         mov ax,4c00h
  20.         int 21h
  21.        
  22. code ends

  23. 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段做实验。
  1. assume cs:code, ds:data, ss:stack

  2. data segment
  3.     dw 0123h,0456h,0123h,0456h,0123h,0456h,0123h,0456h,0123h,0456h
  4. data ends

  5. stack segment
  6.     dw 0,0
  7. stack ends

  8. code segment
  9. start:  mov ax,stack
  10.         mov ss,ax
  11.         mov sp,16
  12.         mov ax,data
  13.         mov ds,ax
  14.         push ds:[0]
  15.         push ds:[2]
  16.         pop  ds:[2]
  17.         pop  ds:[0]               
  18.        
  19.         mov ax,4c00h
  20.         int 21h
  21.        
  22. code ends

  23. 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)
  1. assume cs:code, ds:data, ss:stack

  2. code segment
  3. start:  mov ax,stack
  4.         mov ss,ax
  5.                 mov sp,16
  6.                 mov ax,data
  7.                 mov ds,ax
  8.                 push ds:[0]
  9.         push ds:[2]
  10.         pop  ds:[2]
  11.         pop  ds:[0]               
  12.        
  13.         mov ax,4c00h
  14.         int 21h
  15.        
  16. code ends

  17. data segment
  18.     dw 0123h,0456h
  19. data ends

  20. stack segment
  21.     dw 0,0
  22. stack ends

  23. 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)
  1. assume cs:code

  2. a segment
  3.     db 1,2,3,4,5,6,7,8
  4. a ends

  5. b segment
  6.     db 1,2,3,4,5,6,7,8
  7. b ends       

  8. d segment              ;我用c做段名就报错,无奈,我改成了d,求大佬帮我解答why
  9.     db 0,0,0,0,0,0,0,0
  10. d ends
  11.        
  12. code segment
  13. start:                 
  14.             mov ax,d
  15.                 mov ds,ax      ;将d的段地址给ds
  16.                
  17.                 mov ax,a
  18.                 mov es,ax      ;将a的段地址给es
  19.                
  20.                 mov bx,0
  21.                 mov cx,8
  22.    s1:  mov al,es:[bx]   
  23.         mov [bx],al           ;将a段的值给d段,不用中转al会报错,不能用ax因为ax是2个字节,每个地址只有一个字节,可能出现未知错误
  24.         inc bl
  25.         loop s1
  26.             
  27.         mov ax,b
  28.         mov es,ax      ;将b的段地址给es
  29.                
  30.            mov bx,0
  31.         mov cx,8
  32.    s2:  mov al,es:[bx]     
  33.         add [bx],al             ;将b段的值加给d段
  34.         inc bl
  35.         loop s2
  36.        
  37.         mov ax,4c00h
  38.         int 21h
  39.        
  40. code ends

  41. end start
复制代码

经检验,答案正确

(6)
  1. assume cs:code

  2. a segment
  3.     dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh,0fh,0ffh
  4. a ends

  5. b segment
  6.     dw 0,0,0,0,0,0,0,0
  7. b ends       
  8.        
  9. code segment
  10. start:  mov ax,b      ;把b段视为栈空间
  11.           mov ss,ax
  12.           mov sp,10h   ;直接给b段的末尾地址给sp               
  13.         
  14.           mov ax,a
  15.             mov ds,ax     ;将a段的地址给ds
  16.                
  17.           mov bx,0
  18.           mov cx,8
  19.       s:  push [bx]    ;将a段前8个数据入栈
  20.           add bx,2     ;字型数据加2,两个inc是4个十六进制的代码,而add是3个,所以用add,省空间
  21.           loop s
  22.        
  23.           mov ax,4c00h
  24.           int 21h
  25.        
  26. code ends

  27. end start
复制代码

经检验,答案正确
[u]欢迎留言交流[/u]
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2021-3-19 18:15:52 | 显示全部楼层
前面三道题你的理解有误 程序返回前指的是 debug -t单步运行到下一步执行 int 这一步。。运行了int就是返回了  N个字节占有空间应该是 16X( N/16 +1 )
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-3-30 15:21:38 | 显示全部楼层
最后一问,你只push入栈   逆序排列你没写
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-3-31 10:58:37 | 显示全部楼层
狂热终结者 发表于 2021-3-30 15:21
最后一问,你只push入栈   逆序排列你没写

这个东西,我当时想的是,因为出栈就是逆序的,就没反着入栈,可能当时理解错了。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-5-30 16:50:06 | 显示全部楼层
5.5 其实用一次循环就可以解决,并且a & b端数据重复了,可以double a的
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-6-3 12:27:50 | 显示全部楼层
谢谢楼主,楼主辛苦了,在下佩服,不给截图着实可恶。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-17 01:58:21 | 显示全部楼层
good !!!
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-4-20 21:32:33 | 显示全部楼层
第五题确实坑爹, c不行,改成其他的才行
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-18 22:11

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表