x86汇编语言之段空间大小的对齐

2021-08-24 15:10:21 浏览数 (1)

段所占空间大小和特点

以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'

则内存分布如下:

那么代码会依次连续进行累加填充

0 人点赞