小白的汇编之路(六)----包含多个段的程序

前言

学习王爽老师的汇编语言一书所做的记录
若有不当之处请您指出,您的指点是我的荣幸

安全的空间

相信在学习c语言的时候,老师们都会提醒我们野指针很危险,因为它有可能指向一些未知的内存单元去,如果指向的是一些存有重要数据的内存单元,那么一旦对该单元进行数据修改可能会有惊喜。
汇编语言也一样,不能随意的对内存单元进行操作,那么该如何使用内存空间?

在操作系统的环境中,合法的通过操作系统取得的空间都是安全的,因为操作系统不会让一个程序所用的空间和其他程序以及自己的空间相冲突
程序取得所需空间的方法有两种,这里采用的是在加载程序的时候为程序分配。
比如在加载的时候,取得了代码段中的代码的存储空间
我们若要一个程序在被加载的时候取得所需的空间,则必须要在源程序中作出说明。我们通过在源程序中定义段来进行内存空间的获取。

示例1

例如需要计算这5个数据的和,结果存在ax寄存器中:
0123H,0456H,0789H,0ABCH,0DEFH

assume cs:code
code segment
	dw 0123H,0456H,0789H,0ABCH,0DEFH
	start	mov bx,0
			mov ax,0
			mov cx,5
		s:  add ax,cs:[bx]
			add bx,2
			loop s
			mov ax,4c00h
			int 21h
code ends
end	start	

dw

这里的dw的含义是定义字型数据,也就是define word的意思,数据之间需要使用逗号分分隔
这里将数据写入汇编程序中,当程序被编译连接时,数据会被写入到可执行软件中,并当该软件被加载到内存后,数据会被自动分配内存空间。
而这里因为用dw定义的数据处于代码段的最开始,所以偏移地址为0,这几个数据就在代码段的偏移0,2,4,6,8

这里用dw定义数据,另一方面,也可以说用dw来开辟空间

start

在程序的第一条指令加上了一个标号start,而这个标号在伪指令end的后面出现,这里需要探究下end的作用:

  1. 通知编译器程序结束
  2. 通知编译器程序的入口在什么地方(这里是指明程序的入口在标号start处)

这里需要提及可执行文件中的程序执行过程

  1. 有其他的程序(Debug,command或其它程序)将可执行文件中的程序加载入内存中
  2. 设置CS:IP指向程序的第一条要执行的指令(程序的入口),从而使程序得以运行
  3. 程序运行结束后,返回到加载者

那么是根据什么设置CPU的CS:IP指向程序的第一条要执行的指令?

可执行文件是由描述信息和程序组成的,程序来自于源程序中的汇编指令和定义的数据;描述信息则主要是编译、连接程序对源程序中相关伪指令进行处理所得到的信息
在这个程序中,用伪指令end描述了程序的结束和程序的入口。编译、连接后,由end start指明的程序入口,被转换成一个入口地址,存储在可执行文件的描述信息中。

所以编写程序可以有这样的一种框架

assume cs:code
code segment
		:
		:
		数据
		:
		:
start:
		:
		:
		代码
		:
		:
code ends
end start			

有这么一个例子:
利用栈将程序中定义的数据逆序排放

assume cs:codesg
codesg segment
	# 这里是将 cs:[00]~cs:[0f]用于存储8个数据
	dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
	# 这里是将 cs:[10]~cs:[2f]当栈
	dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
# start与后面的end start 用于表示这是程序的第一行指令
start: 	mov ax,cs
		mov ss,ax
		# 这里是设置ss:sp指向栈底,因为初始时这个栈是空的
		mov sp,30h
	
		# 设置偏移地址
		mov bx,0
		# 设置循环次数
		mov cx,8
		# 将 cs:[bx]指向的内存单元中的值入栈
	s: 	push cs:[bx]
		# 到下一个数据
		add bx,2
		# 循环
		loop s
		
		# 重置偏移地址
		mov bx,0
		# 设置循环次数
		mov cx,8
		# 出栈并将值送入 cs:[bx]指向的内存单元
	s0: pop cs:[bx]
		add bx,2
		# 循环
		loop s0

		mov ax,4c00h
		int 21h
		
codesg ends
end start						

我们可以这样将数据和代码都放到一个段中,但是在8086CPU中,一个段的容量是不能大于64KB的,这是8086模式的限制,并不是所有处理器都是这样的。
而且将数据和代码,栈都放在一个段中会显得混乱,所以应该考虑使用多个段来存放数据,代码和栈。
将数据,代码,栈放入不同的段中可以这样写:

# 这里是将这些段与相关的寄存器联系起来,assume不必深究
assume cs:code,ds:data,ss:stack
data segment
	dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
data ends
stack segment
	dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
stack ends
code segment
# mov ax,stack 的含义就是将名称为data的段的段地址送入ax
# 下面的mov ax,data同理
# 值得注意的是,不能直接将一个数值直接送入段寄存器中!!!
start: 	mov ax,stack
		mov ss,ax
		mov sp,20h	

		mov ax,data
		mov ds,ax
	
		mov bx,0
		
		mov cx,8
	s:	push [bx]
		add bx,2
		loop s

		mov bx,0
		
		mov cx,8
	s0:	pop [bx]
		add bx,2
		loop s0
		
		mov ax,4c00h
		int 21h

code ends
end start	
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值