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
对于如下定义的段:
name segment
...
name ends
如果短中的数据占N个字节,则程序加载后,该段实际占有的空间为:______。
16 个解决方案
#1
如果短中的数据占N个字节,则程序加载后,该段实际占有的空间为:(N/16+1)*16 [说明:N/16只取整数部分]
#2
讲原理
#3
我给你个偏门技巧:(N+15)/16后取整*16。。。建议要自己搞懂,不建议照搬!
#4
看王师傅“段的概念”那节,详细点看。。。那段里还有特别提醒。。。
#5
哎 谁来个直接的回答分就拿走
#6
(N+15)&~15;//间接的
他们的是直接的。
#7
对于如下定义的段:
name segment
...
name ends
如果短中的数据占N个字节,则程序加载后,该段实际占有的空间为:______。
[[[[[[如果短中的数据占N个字节,则程序加载后,该段实际占有的空间为:(N/16+1)*16 [说明:N/16只取整数部分] ]]]]]]]]]
王爽提此问题是个几乎没有任何价值的问题,因为数据段最后一行剩下几格,程序设计时几乎从不考虑。
比如n=33个字节,你用debug时看到的内存格子每行是16格,这时第33个字要放在第三行第0位,这1个字节就占用了第三行,你再定义另一个name2数据段时,masm会把它从第四行放起;所以n=33就占掉了(33/16+1)*16=48个字节,即3行*16=48。
另外,设计程序时最好用debug查看实际位置后修改si,di,bx等,因为有时数据前会被插个回车符,你如果不查看实际位置而完全按(N/16+1)*16去计算位置,那不久你就会被气得放弃汇编语言,正如罗云彬所说的,很多人被寻址计算搞得一头雾水,实际上是写书的人没把书写好。
name segment
...
name ends
如果短中的数据占N个字节,则程序加载后,该段实际占有的空间为:______。
[[[[[[如果短中的数据占N个字节,则程序加载后,该段实际占有的空间为:(N/16+1)*16 [说明:N/16只取整数部分] ]]]]]]]]]
王爽提此问题是个几乎没有任何价值的问题,因为数据段最后一行剩下几格,程序设计时几乎从不考虑。
比如n=33个字节,你用debug时看到的内存格子每行是16格,这时第33个字要放在第三行第0位,这1个字节就占用了第三行,你再定义另一个name2数据段时,masm会把它从第四行放起;所以n=33就占掉了(33/16+1)*16=48个字节,即3行*16=48。
另外,设计程序时最好用debug查看实际位置后修改si,di,bx等,因为有时数据前会被插个回车符,你如果不查看实际位置而完全按(N/16+1)*16去计算位置,那不久你就会被气得放弃汇编语言,正如罗云彬所说的,很多人被寻址计算搞得一头雾水,实际上是写书的人没把书写好。
#8
一、这首先要从8086处理器寻址原理说起。
8086这种处理器有二十根地址线(20个用于寻址的管脚),可以使用的外部存储器空间可达1MB(00000H~FFFFFH)。
但是,8086内部的寄存器都是16位的,用任何一个寄存器(比如BX或SI),都无法直接寻址8086所支持的1M地址空间,因为16位寄存器只能表示640KB的空间范围(0000~FFFFH)。
所以,Intel想了一个方法,设计出了CS/DS/ES/SS这几个段地址寄存器,用段地址寄存器与普通寄存器组合,来寻址1MB的地址范围,即:对于CPU取指来说,用CS:IP组合来寻址下一个要执行的指令(也在存储器中);对于堆栈操作PUSH/POP来说,用SS:SP组合来表示当前栈指针(栈也在存储器中);对于数据操作指令来说,用默认的DS/ES或指定的段地址(段前缀指令)与偏移量寄存器组合寻址。
组合后的实际地址=段寄存器内容×16+偏移量寄存器内容
从这个公式可以看到,每一个段的地址都对齐在16的倍数上。比如DS=1234H,则这个段就从
1234H×16+0000H=12340H开始,最大到1234H×16+0FFFFH=2233FH为止。
二、对同一个内存地址,有不同的段:偏移量组合方法,比如2233FH这个地址,既可以表示为1234H:0FFFFH(在1234H段中),也可以表示为2233H:0000FH(在2233H段中)。
那么,如果汇编程序中有下面两个连续的段定义,汇编编译程序会怎么做呢?
name1 segment
d1 db 0
name1 ends
name2 segment
d2 db 0
name2 ends
编译程序可以将name1和name2编译成一个段,d1和d2在内存中连续存放,这样可以节省内存空间。比如编译程序以name1为基准,将name1作为一个段的起始,程序加载后会被放在xxxx0H的地方,那么d1就放在该段偏移地址为0字节的位置,d2就放在该段偏移为1字节的位置。
这样的处理方式虽然可能会节省一点内存空间,但是对于编译器的智能化要求太高了,它必须将源程序中所有引用到name2和d2的地方,全部调整为以name1段为基准,这实在是太难了,而且也节省不了几个字节的空间,编译器是不会干这种吃力不讨好的事的。编译器实际的处理方式是将name1中的所有内容放在一个段的起始地址处,name2里的所有内容放在后续一个段的起始地址处(这也是汇编指令segment的本义:将不同数据分段)。这样,即使name1中只包含一个字节,也要占一个段(16个字节),所以,一个段实际占用的空间=(段中字节数+15)/ 16。
所以,8086处理器的内部寻址原理和汇编程序编译器共同决定了segment定义的段必须放在按16的倍数对准的段地址边界上,占用的空间也是16的倍数。
8086这种处理器有二十根地址线(20个用于寻址的管脚),可以使用的外部存储器空间可达1MB(00000H~FFFFFH)。
但是,8086内部的寄存器都是16位的,用任何一个寄存器(比如BX或SI),都无法直接寻址8086所支持的1M地址空间,因为16位寄存器只能表示640KB的空间范围(0000~FFFFH)。
所以,Intel想了一个方法,设计出了CS/DS/ES/SS这几个段地址寄存器,用段地址寄存器与普通寄存器组合,来寻址1MB的地址范围,即:对于CPU取指来说,用CS:IP组合来寻址下一个要执行的指令(也在存储器中);对于堆栈操作PUSH/POP来说,用SS:SP组合来表示当前栈指针(栈也在存储器中);对于数据操作指令来说,用默认的DS/ES或指定的段地址(段前缀指令)与偏移量寄存器组合寻址。
组合后的实际地址=段寄存器内容×16+偏移量寄存器内容
从这个公式可以看到,每一个段的地址都对齐在16的倍数上。比如DS=1234H,则这个段就从
1234H×16+0000H=12340H开始,最大到1234H×16+0FFFFH=2233FH为止。
二、对同一个内存地址,有不同的段:偏移量组合方法,比如2233FH这个地址,既可以表示为1234H:0FFFFH(在1234H段中),也可以表示为2233H:0000FH(在2233H段中)。
那么,如果汇编程序中有下面两个连续的段定义,汇编编译程序会怎么做呢?
name1 segment
d1 db 0
name1 ends
name2 segment
d2 db 0
name2 ends
编译程序可以将name1和name2编译成一个段,d1和d2在内存中连续存放,这样可以节省内存空间。比如编译程序以name1为基准,将name1作为一个段的起始,程序加载后会被放在xxxx0H的地方,那么d1就放在该段偏移地址为0字节的位置,d2就放在该段偏移为1字节的位置。
这样的处理方式虽然可能会节省一点内存空间,但是对于编译器的智能化要求太高了,它必须将源程序中所有引用到name2和d2的地方,全部调整为以name1段为基准,这实在是太难了,而且也节省不了几个字节的空间,编译器是不会干这种吃力不讨好的事的。编译器实际的处理方式是将name1中的所有内容放在一个段的起始地址处,name2里的所有内容放在后续一个段的起始地址处(这也是汇编指令segment的本义:将不同数据分段)。这样,即使name1中只包含一个字节,也要占一个段(16个字节),所以,一个段实际占用的空间=(段中字节数+15)/ 16。
所以,8086处理器的内部寻址原理和汇编程序编译器共同决定了segment定义的段必须放在按16的倍数对准的段地址边界上,占用的空间也是16的倍数。
#9
解释得太好了,刚好在学习这个东西.
#10
这几天搞汇编,头都大了,..
#11
哈哈~这样的确管用哦!
你要的应该是这句:
[color=#FF0000]即使name1中只包含一个字节,也要占一个段(16个字节)[color]
就是说要保证是16的倍数。所以就有了(N+15)/16 *16这样的算法
#12
哈哈~这样的确管用哦!
你要的应该是这句:
[color=#FF0000]即使name1中只包含一个字节,也要占一个段(16个字节)[color]
就是说要保证是16的倍数。所以就有了(N+15)/16 *16这样的算法
#13
哈哈~这样的确管用哦!
你要的应该是这句:
[color=#FF0000]即使name1中只包含一个字节,也要占一个段(16个字节)[color]
就是说要保证是16的倍数。所以就有了(N+15)/16 *16这样的算法
#14
顶8楼,我看懂了哈。
#15
已忘记……
#16
同样的问题总是有人翻来覆去的问。。。很无语、、、
#1
如果短中的数据占N个字节,则程序加载后,该段实际占有的空间为:(N/16+1)*16 [说明:N/16只取整数部分]
#2
讲原理
#3
我给你个偏门技巧:(N+15)/16后取整*16。。。建议要自己搞懂,不建议照搬!
#4
看王师傅“段的概念”那节,详细点看。。。那段里还有特别提醒。。。
#5
哎 谁来个直接的回答分就拿走
#6
(N+15)&~15;//间接的
他们的是直接的。
#7
对于如下定义的段:
name segment
...
name ends
如果短中的数据占N个字节,则程序加载后,该段实际占有的空间为:______。
[[[[[[如果短中的数据占N个字节,则程序加载后,该段实际占有的空间为:(N/16+1)*16 [说明:N/16只取整数部分] ]]]]]]]]]
王爽提此问题是个几乎没有任何价值的问题,因为数据段最后一行剩下几格,程序设计时几乎从不考虑。
比如n=33个字节,你用debug时看到的内存格子每行是16格,这时第33个字要放在第三行第0位,这1个字节就占用了第三行,你再定义另一个name2数据段时,masm会把它从第四行放起;所以n=33就占掉了(33/16+1)*16=48个字节,即3行*16=48。
另外,设计程序时最好用debug查看实际位置后修改si,di,bx等,因为有时数据前会被插个回车符,你如果不查看实际位置而完全按(N/16+1)*16去计算位置,那不久你就会被气得放弃汇编语言,正如罗云彬所说的,很多人被寻址计算搞得一头雾水,实际上是写书的人没把书写好。
name segment
...
name ends
如果短中的数据占N个字节,则程序加载后,该段实际占有的空间为:______。
[[[[[[如果短中的数据占N个字节,则程序加载后,该段实际占有的空间为:(N/16+1)*16 [说明:N/16只取整数部分] ]]]]]]]]]
王爽提此问题是个几乎没有任何价值的问题,因为数据段最后一行剩下几格,程序设计时几乎从不考虑。
比如n=33个字节,你用debug时看到的内存格子每行是16格,这时第33个字要放在第三行第0位,这1个字节就占用了第三行,你再定义另一个name2数据段时,masm会把它从第四行放起;所以n=33就占掉了(33/16+1)*16=48个字节,即3行*16=48。
另外,设计程序时最好用debug查看实际位置后修改si,di,bx等,因为有时数据前会被插个回车符,你如果不查看实际位置而完全按(N/16+1)*16去计算位置,那不久你就会被气得放弃汇编语言,正如罗云彬所说的,很多人被寻址计算搞得一头雾水,实际上是写书的人没把书写好。
#8
一、这首先要从8086处理器寻址原理说起。
8086这种处理器有二十根地址线(20个用于寻址的管脚),可以使用的外部存储器空间可达1MB(00000H~FFFFFH)。
但是,8086内部的寄存器都是16位的,用任何一个寄存器(比如BX或SI),都无法直接寻址8086所支持的1M地址空间,因为16位寄存器只能表示640KB的空间范围(0000~FFFFH)。
所以,Intel想了一个方法,设计出了CS/DS/ES/SS这几个段地址寄存器,用段地址寄存器与普通寄存器组合,来寻址1MB的地址范围,即:对于CPU取指来说,用CS:IP组合来寻址下一个要执行的指令(也在存储器中);对于堆栈操作PUSH/POP来说,用SS:SP组合来表示当前栈指针(栈也在存储器中);对于数据操作指令来说,用默认的DS/ES或指定的段地址(段前缀指令)与偏移量寄存器组合寻址。
组合后的实际地址=段寄存器内容×16+偏移量寄存器内容
从这个公式可以看到,每一个段的地址都对齐在16的倍数上。比如DS=1234H,则这个段就从
1234H×16+0000H=12340H开始,最大到1234H×16+0FFFFH=2233FH为止。
二、对同一个内存地址,有不同的段:偏移量组合方法,比如2233FH这个地址,既可以表示为1234H:0FFFFH(在1234H段中),也可以表示为2233H:0000FH(在2233H段中)。
那么,如果汇编程序中有下面两个连续的段定义,汇编编译程序会怎么做呢?
name1 segment
d1 db 0
name1 ends
name2 segment
d2 db 0
name2 ends
编译程序可以将name1和name2编译成一个段,d1和d2在内存中连续存放,这样可以节省内存空间。比如编译程序以name1为基准,将name1作为一个段的起始,程序加载后会被放在xxxx0H的地方,那么d1就放在该段偏移地址为0字节的位置,d2就放在该段偏移为1字节的位置。
这样的处理方式虽然可能会节省一点内存空间,但是对于编译器的智能化要求太高了,它必须将源程序中所有引用到name2和d2的地方,全部调整为以name1段为基准,这实在是太难了,而且也节省不了几个字节的空间,编译器是不会干这种吃力不讨好的事的。编译器实际的处理方式是将name1中的所有内容放在一个段的起始地址处,name2里的所有内容放在后续一个段的起始地址处(这也是汇编指令segment的本义:将不同数据分段)。这样,即使name1中只包含一个字节,也要占一个段(16个字节),所以,一个段实际占用的空间=(段中字节数+15)/ 16。
所以,8086处理器的内部寻址原理和汇编程序编译器共同决定了segment定义的段必须放在按16的倍数对准的段地址边界上,占用的空间也是16的倍数。
8086这种处理器有二十根地址线(20个用于寻址的管脚),可以使用的外部存储器空间可达1MB(00000H~FFFFFH)。
但是,8086内部的寄存器都是16位的,用任何一个寄存器(比如BX或SI),都无法直接寻址8086所支持的1M地址空间,因为16位寄存器只能表示640KB的空间范围(0000~FFFFH)。
所以,Intel想了一个方法,设计出了CS/DS/ES/SS这几个段地址寄存器,用段地址寄存器与普通寄存器组合,来寻址1MB的地址范围,即:对于CPU取指来说,用CS:IP组合来寻址下一个要执行的指令(也在存储器中);对于堆栈操作PUSH/POP来说,用SS:SP组合来表示当前栈指针(栈也在存储器中);对于数据操作指令来说,用默认的DS/ES或指定的段地址(段前缀指令)与偏移量寄存器组合寻址。
组合后的实际地址=段寄存器内容×16+偏移量寄存器内容
从这个公式可以看到,每一个段的地址都对齐在16的倍数上。比如DS=1234H,则这个段就从
1234H×16+0000H=12340H开始,最大到1234H×16+0FFFFH=2233FH为止。
二、对同一个内存地址,有不同的段:偏移量组合方法,比如2233FH这个地址,既可以表示为1234H:0FFFFH(在1234H段中),也可以表示为2233H:0000FH(在2233H段中)。
那么,如果汇编程序中有下面两个连续的段定义,汇编编译程序会怎么做呢?
name1 segment
d1 db 0
name1 ends
name2 segment
d2 db 0
name2 ends
编译程序可以将name1和name2编译成一个段,d1和d2在内存中连续存放,这样可以节省内存空间。比如编译程序以name1为基准,将name1作为一个段的起始,程序加载后会被放在xxxx0H的地方,那么d1就放在该段偏移地址为0字节的位置,d2就放在该段偏移为1字节的位置。
这样的处理方式虽然可能会节省一点内存空间,但是对于编译器的智能化要求太高了,它必须将源程序中所有引用到name2和d2的地方,全部调整为以name1段为基准,这实在是太难了,而且也节省不了几个字节的空间,编译器是不会干这种吃力不讨好的事的。编译器实际的处理方式是将name1中的所有内容放在一个段的起始地址处,name2里的所有内容放在后续一个段的起始地址处(这也是汇编指令segment的本义:将不同数据分段)。这样,即使name1中只包含一个字节,也要占一个段(16个字节),所以,一个段实际占用的空间=(段中字节数+15)/ 16。
所以,8086处理器的内部寻址原理和汇编程序编译器共同决定了segment定义的段必须放在按16的倍数对准的段地址边界上,占用的空间也是16的倍数。
#9
解释得太好了,刚好在学习这个东西.
#10
这几天搞汇编,头都大了,..
#11
哈哈~这样的确管用哦!
你要的应该是这句:
[color=#FF0000]即使name1中只包含一个字节,也要占一个段(16个字节)[color]
就是说要保证是16的倍数。所以就有了(N+15)/16 *16这样的算法
#12
哈哈~这样的确管用哦!
你要的应该是这句:
[color=#FF0000]即使name1中只包含一个字节,也要占一个段(16个字节)[color]
就是说要保证是16的倍数。所以就有了(N+15)/16 *16这样的算法
#13
哈哈~这样的确管用哦!
你要的应该是这句:
[color=#FF0000]即使name1中只包含一个字节,也要占一个段(16个字节)[color]
就是说要保证是16的倍数。所以就有了(N+15)/16 *16这样的算法
#14
顶8楼,我看懂了哈。
#15
已忘记……
#16
同样的问题总是有人翻来覆去的问。。。很无语、、、