635924705 发表于 2021-2-5 22:53:37

汇编语言_实验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
经检验,答案正确
欢迎留言交流

qq904641971 发表于 2021-3-19 18:15:52

前面三道题你的理解有误 程序返回前指的是 debug -t单步运行到下一步执行 int 这一步。。运行了int就是返回了N个字节占有空间应该是 16X( N/16 +1 )

狂热终结者 发表于 2021-3-30 15:21:38

最后一问,你只push入栈   逆序排列你没写

635924705 发表于 2021-3-31 10:58:37

狂热终结者 发表于 2021-3-30 15:21
最后一问,你只push入栈   逆序排列你没写

这个东西,我当时想的是,因为出栈就是逆序的,就没反着入栈,可能当时理解错了。{:10_262:}

fishc_ceo 发表于 2021-5-30 16:50:06

5.5 其实用一次循环就可以解决,并且a & b端数据重复了,可以double a的

15144201190 发表于 2021-6-3 12:27:50

谢谢楼主,楼主辛苦了,在下佩服,不给截图着实可恶。

daywalker911 发表于 2021-11-17 01:58:21

good !!!{:10_249:}

孙尐爷 发表于 2023-4-20 21:32:33

第五题确实坑爹, c不行,改成其他的才行
页: [1]
查看完整版本: 汇编语言_实验5(超详细)