段所占空间大小和特点
以8086为例,假如声明一个段,不论是数据段,栈段还是代码段, 一旦段里面有内容,那么会从一个新的段地址开始开辟空间,如果代码进行了分段处理,那么就会形成16字节对齐的现象
代码语言:javascript复制assume ds:data
;场景一
data segment
;如果没有内容,则不开辟空间, 被编译器忽略
data ends
;场景二
data segment
dw 55FFH,55FFH ;后面的数据用0补足16个字节
data ends
;场景三
data segment
dw 55FFH,55FFH
db 'hello' ;以上占用连续的内存空间 55FFH 55FFH hello
data ends
;场景四
data segment
dw 55FFH,55FFH,55FFH,55FFH,55FFH,55FFH,55FFH,55FFH,55FFH,55FFH,55FFH,55FFH;超过16个字节,那么开辟16的倍数也就是32个字节的空间, 以此类推
data ends
段空间占用计算公式:
如果段中的数据占用N个字节,则程序加载后,该段实际占用空间为:
代码语言:javascript复制(N/16 1)*16
为什么说是现象呢
本质并不是因为段固定占用n16字节,而是因为段必须从一个新的地址段开始开辟空间,这就导致了我们认为*段一次最少拉升16字节的内存空间,必须为16的倍数**, 原因看如下代码:
代码语言:javascript复制
data segment
db 'hello'
data ends
start:
call print
mov ax,2000H
print:
mov bx,3000H
mov cx,4000H
ret
end start
内存分布如下:
我们发现data段并没有独占16个字节空间,而是让数据从一个新的16字节地址开始存入,段的作用是让数据在内存中的排列按照一定的布局进行排列,方便我们进行计算读取, 但是使用段的话明显会占用更多的内存空间
各个段之间内存排列分布
数据段,栈段,代码段 他们在内存中开辟的空间是根据代码由上到下依次分布的:
代码语言:javascript复制assume ds:data,cs:code,ss:stack
data segment
dw 66FF
data ends
;假如数据段的段地址是2000H 那么栈段的段地址为2001H, 代码段的段地址为:2002H 依次排列
stack segment
dw 77FF
stack ends
code segment
mov ax,data
mov ds,ax
mov ax,stack
mov ss,ax
code ends
;数据段--->栈段--->代码段
假如数据段的段地址是2000H 那么栈段的段地址为2001H, 代码段的段地址为:2002H 依次排列
如果我将各个段的代码位置调整一下,那么所在内存的位置也会跟着发生改变:
代码语言:javascript复制assume ds:data,cs:code,ss:stack
;假如栈段的段地址是2000H 那么代码段的段地址为2001H, 数据段的段地址为:2002H 依次排列
stack segment
dw 77FF
stack ends
code segment
mov ax,data
mov ds,ax
mov ax,stack
mov ss,ax
code ends
data segment
dw 66FF
data ends
;栈段--->代码段--->数据段
也就是说各个段的内存分布不是固定的, 和代码的编写有关系
如果不加start标记的话,汇编代码默认由上往下执行,cs ip从上往下,所过之处,全部被当做代码处理, 因此即便你在数据段中存放指令,甚至打入代码起始标签也没有问题:
代码语言:javascript复制assume cs:code,ds:data
data segment
mov ax,2000H ;第一步 执行
data ends
;由于一个段所占空间为16的倍数,后面空位补0,被当做为指令对待,因此当在数据段中执行16个字节代码后,由于段与段之间内存是连续分布的,如果ip的值刚好指向了代码段,那么紧接着执行代码段中的内容,如果ip没有指向代码段,则不执行, 这个情况是不可控的
code segment
mov ax,3000H ;ip偏移16个字节后 执行
code ends
如果在数据段中加上代码起始标记:
代码语言:javascript复制assume cs:code,ds:data
data segment
dw 55FFH
start:
mov ax,2000H ;第一步 先执行 如果没有标记,则从dw开始当做代码执行
data ends
code segment
mov ax,3000H ;ip偏移16个字节后 执行
code ends
end start
段和段地址之间的关系
每个段会独占一个栈地址
代码语言:javascript复制assume cs:code,ds:data
mov ax,3000H ;占用三个字节空间
data segment
age dw 'hello'
data ends
内存分布如下:
咱们会发现数据段,并不是从0100:0003开始开辟16个字节的空间,而是新起一个段地址从0101:0000开始开辟, 也就是说一个段占用独立的一个栈地址
假如把段去掉:
代码语言:javascript复制assume cs:code,ds:data
mov ax,3000H ;占用三个字节空间
age dw 'hello'
则内存分布如下:
那么代码会依次连续进行累加填充