做网站时无法上传图片/宁波怎么优化seo关键词
《汇编语言》第六章主要讲述“如何编写包含多个段的汇编源程序”。本章的文字内容不多,主要通过编程实践来理解汇编源程序架构的含义,通篇学下来,我觉得有以下几点需要理解清楚:
1,这里所说的多个段(segment),从汇编“程序”的角度来说,它指的是程序所占用的内存空间的划分,大致分为:data segment、stack segment和code segment。其实际就是指定运行时CPU的DS、SS和CS这三个寄存器的值。
2,但是,从源程序的角度来看,它指的是代码的组织方式。源程序分成多个段,是的代码的层次更清晰。
3,我们通常讲的多个段,更多的还是从源程序的角度来说的。事实上,一个段的源程序,通过设置CPU的寄存器也可以划分程序的内存空间。
4,汇编语言通过在源程序中使用段名(name)来标记各个段。
5,源程序中的段名(name)和标号(label),它们本质上都代表一个地址。在debug下反汇编,我们可以看到,段名和标号都被它们代码的地址值替代了。
6,不同的是,段名代表的是段地址(SA),标号代表的是偏移地址(EA)。
7,源程序通过“end+label”指定入口地址(entry),当然,这个入口地址仅仅是偏移地址。默认为0。
8,这个入口地址的信息被记录在.exe的描述信息中,对应“PSP(程序段前缀)”。
9,程序加载的时候,CS由系统指定(或者说由加载程序指定,shell);加载程序会搜索PSP,根据其中的entry,设置IP的值,默认为0。
10,严格来说,单段的程序只需要根据entry修改IP的值,多段的程序,则需要修改CS的值,CS的值按16位对齐,IP的值为0。
11,IP的值为16位,范围为0-255,它能开辟的空间有限,故单段的程序不适合需要大内存的应用。而CS表示段地址,它的变化范围就比较广了,可以开大得多的内存空间。
本章的重点在于编程实践,下面我将介绍我的编程实践。
检测点6.1
程序补全
(1)内存复制
assume cs:codesg
codesg segmentdw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987hstart:mov ax,0mov ds,axmov bx,0mov cx,8s:mov ax,[bx]<span style="color:#ff0000;">mov cs:[bx],ax</span>add bx,2loop smov ax,4c00hint 21h
codesg ends
end start
(2)使用栈进行内存复制
assume cs:codesg
codesg segmentdw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987hdw 0,0,0,0,0,0,0,0,0,0start:mov ax,csmov ss,axmov sp,36mov ax,0mov ds,axmov bx,0mov cx,8s:push [bx]pop cs:[bx]add bx,2loop smov ax,4c00hint 21h
codesg ends
end start
以上两个程序都是单段程序,这个不是主流,我就不详细讲解了。
实验5
1,程序调试
问题回答:
1)CPU执行程序,程序返回前,data段中的数据不变;
2)CS=
3)设程序加载后,code段的段地址为X,则data段的段地址为X-16 ,stack段的段地址为X-32
如上图,重点观察程序执行前后,ds、ss、cs和ip这几个寄存器的值。分析如下:
1)程序加载后,执行前,ds=0cd7h,ss=0ce7h,cs=0ce9h,ip=0000h
根据第4章的知识可知,ds:0指向程序内存空间起始地址,或PSP首地址,而PSP为256Byte,故SS初始化时为0ce7h,即ss:0 - ds:0 = 256。本来cs的值也应该是0ce7h,但是该程序的源码中用“end+start”改变了入口地址。如果是在单段的程序,仅修改IP的值,但是这是一个多段的程序,直接修改了cs的值。
cs:0 - ss:0 = 20h。这个20h刚好是data segment和stack segment所占的空间大小。
需要注意的是:cs的值会保持16位对齐。也就是说,我们在源码中,删除几个(小于16)data segment或stack segment中的元素,重新编译、链接和加载后,在debug下查看,cs的值还是0ce9。至于那段空间,会自动补0,进行填充。
2)程序执行后,ds=0ce7,ss=0ce8,cs=0ce9
ds和ss的值的变化实际上是程序执行的结果,即是程序员自己编写指令修改它们的。
2,程序调试
这道程序调试题,与上一道相似,它的重点在问题4。实际上,它要表达的意思是:data segment、stack segment和code segment的段地址会按16位对齐。
如果一个段中的数据占N个字节,则程序加载后,该段实际占有的空间为“ceil(N/16) * 16”。
3,程序调试
assume cs:code,ds:data,ss:stackcode segmentstart:mov ax,stackmov ss,axmov sp,16mov ax,datamov ds,axpush ds:[0]push ds:[2]pop ds:[2]pop ds:[0]mov ax,4c00hint 21h
code endsdata segmentdw 0123h,0456h
data ends
stack segmentdw 0,0
stack endsend start
这个程序是在上一道程序的基础上,调换源程序中各个段的顺序。debug如下:
如上图,重点观察程序执行前后,ds、ss、cs这几个寄存器的值。分析如下:
1)程序加载后,执行前,ds=0cd2h,ss=0ce6h,cs=0ce2h
根据第4章的知识可知,ds:0指向程序内存空间起始地址,或PSP首地址,而PSP为256Byte,故CS初始化时为0ce7h,即cs:0 - ds:0 = 256。
这个程序编译后,cs段提到了第一位。
2)程序执行后,ds=0ce5,ss=0ce6,cs=0ce2
ds和ss的值的变化实际上是程序执行的结果,即是程序员自己编写指令修改它们的。
这道题的目的是要说明,在编译器看来,段名仅仅只是一种标记,谁排在前谁排在后,由源码的位置决定(编译先后不同)。
3)该程序,即使将“end start”改变为“end”,也不影响编译结果。
5,编程题(求和)
assume cs:code
a segmentdb 1,2,3,4,5,6,7,8
a ends
b segmentdb 1,2,3,4,5,6,7,8
b ends
c segmentdb 0,0,0,0,0,0,0,0
c endscode segmentstart:mov bx,0mov cx,8s:mov ax,amov ds,axmov dx,[bx]mov ax,bmov ds,axadd dx,[bx]mov ax,cmov ds,axmov [bx],dxinc bxloop smov ax,4c00hint 21h
code ends
end start
6,编程题(逆序复制)
assume cs:codea segmentdw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh,0fh,0ffh
a endsb segmentdw 0,0,0,0,0,0,0,0
b endscode segmentstart:mov ax,amov ds,axmov ax,bmov ss,axmov sp,10hmov bx,0mov cx,8s:mov ax,[bx]push axadd bx,2loop smov ax,4c00hint 21h
code ends
end start