前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >x86汇编语言之段空间大小的对齐

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

作者头像
乱码三千
发布2021-08-24 15:10:21
8010
发布2021-08-24 15:10:21
举报
文章被收录于专栏:乱码三千乱码三千

段所占空间大小和特点

以8086为例,假如声明一个段,不论是数据段,栈段还是代码段, 一旦段里面有内容,那么会从一个新的段地址开始开辟空间,如果代码进行了分段处理,那么就会形成16字节对齐现象

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个字节,则程序加载后,该段实际占用空间为:

(N/16+1)*16
为什么说是现象呢

本质并不是因为段固定占用n16字节,而是因为段必须从一个新的地址段开始开辟空间,这就导致了我们认为*段一次最少拉升16字节的内存空间,必须为16的倍数**, 原因看如下代码:


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字节地址开始存入,段的作用是让数据在内存中的排列按照一定的布局进行排列,方便我们进行计算读取, 但是使用段的话明显会占用更多的内存空间

各个段之间内存排列分布

数据段,栈段,代码段 他们在内存中开辟的空间是根据代码由上到下依次分布的:

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 依次排列

如果我将各个段的代码位置调整一下,那么所在内存的位置也会跟着发生改变:

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从上往下,所过之处,全部被当做代码处理, 因此即便你在数据段中存放指令,甚至打入代码起始标签也没有问题:

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

如果在数据段中加上代码起始标记:

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

段和段地址之间的关系

每个段会独占一个栈地址

assume cs:code,ds:data
                         
 mov ax,3000H  ;占用三个字节空间
 
 data segment                 
 	age dw 'hello'     
 data ends

内存分布如下:

咱们会发现数据段,并不是从0100:0003开始开辟16个字节的空间,而是新起一个段地址从0101:0000开始开辟, 也就是说一个段占用独立的一个栈地址

假如把段去掉:

assume cs:code,ds:data
                         
 mov ax,3000H  ;占用三个字节空间
              
 age dw 'hello'

则内存分布如下:

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-08-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 乱码三千 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 段所占空间大小和特点
    • 段空间占用计算公式:
      • 为什么说是现象呢
      • 各个段之间内存排列分布
      • 段和段地址之间的关系
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档